2021-12-22 03:59:27 +00:00
|
|
|
#!/bin/sh
|
|
|
|
|
|
|
|
test_description='git-hook command'
|
|
|
|
|
|
|
|
TEST_PASSES_SANITIZE_LEAK=true
|
|
|
|
. ./test-lib.sh
|
2022-06-07 08:48:20 +00:00
|
|
|
. "$TEST_DIRECTORY"/lib-terminal.sh
|
2021-12-22 03:59:27 +00:00
|
|
|
|
|
|
|
test_expect_success 'git hook usage' '
|
|
|
|
test_expect_code 129 git hook &&
|
|
|
|
test_expect_code 129 git hook run &&
|
|
|
|
test_expect_code 129 git hook run -h &&
|
|
|
|
test_expect_code 129 git hook run --unknown 2>err &&
|
|
|
|
grep "unknown option" err
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'git hook run: nonexistent hook' '
|
|
|
|
cat >stderr.expect <<-\EOF &&
|
|
|
|
error: cannot find a hook named test-hook
|
|
|
|
EOF
|
|
|
|
test_expect_code 1 git hook run test-hook 2>stderr.actual &&
|
|
|
|
test_cmp stderr.expect stderr.actual
|
|
|
|
'
|
|
|
|
|
2021-12-22 03:59:37 +00:00
|
|
|
test_expect_success 'git hook run: nonexistent hook with --ignore-missing' '
|
|
|
|
git hook run --ignore-missing does-not-exist 2>stderr.actual &&
|
|
|
|
test_must_be_empty stderr.actual
|
|
|
|
'
|
|
|
|
|
2021-12-22 03:59:27 +00:00
|
|
|
test_expect_success 'git hook run: basic' '
|
2022-03-17 10:13:06 +00:00
|
|
|
test_hook test-hook <<-EOF &&
|
2021-12-22 03:59:27 +00:00
|
|
|
echo Test hook
|
|
|
|
EOF
|
|
|
|
|
|
|
|
cat >expect <<-\EOF &&
|
|
|
|
Test hook
|
|
|
|
EOF
|
|
|
|
git hook run test-hook 2>actual &&
|
|
|
|
test_cmp expect actual
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'git hook run: stdout and stderr both write to our stderr' '
|
2022-03-17 10:13:06 +00:00
|
|
|
test_hook test-hook <<-EOF &&
|
2021-12-22 03:59:27 +00:00
|
|
|
echo >&1 Will end up on stderr
|
|
|
|
echo >&2 Will end up on stderr
|
|
|
|
EOF
|
|
|
|
|
|
|
|
cat >stderr.expect <<-\EOF &&
|
|
|
|
Will end up on stderr
|
|
|
|
Will end up on stderr
|
|
|
|
EOF
|
|
|
|
git hook run test-hook >stdout.actual 2>stderr.actual &&
|
|
|
|
test_cmp stderr.expect stderr.actual &&
|
|
|
|
test_must_be_empty stdout.actual
|
|
|
|
'
|
|
|
|
|
2022-03-17 10:13:07 +00:00
|
|
|
for code in 1 2 128 129
|
|
|
|
do
|
|
|
|
test_expect_success "git hook run: exit code $code is passed along" '
|
|
|
|
test_hook test-hook <<-EOF &&
|
|
|
|
exit $code
|
|
|
|
EOF
|
|
|
|
|
|
|
|
test_expect_code $code git hook run test-hook
|
|
|
|
'
|
|
|
|
done
|
2021-12-22 03:59:27 +00:00
|
|
|
|
|
|
|
test_expect_success 'git hook run arg u ments without -- is not allowed' '
|
|
|
|
test_expect_code 129 git hook run test-hook arg u ments
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'git hook run -- pass arguments' '
|
2022-03-17 10:13:06 +00:00
|
|
|
test_hook test-hook <<-\EOF &&
|
2021-12-22 03:59:27 +00:00
|
|
|
echo $1
|
|
|
|
echo $2
|
|
|
|
EOF
|
|
|
|
|
|
|
|
cat >expect <<-EOF &&
|
|
|
|
arg
|
|
|
|
u ments
|
|
|
|
EOF
|
|
|
|
|
|
|
|
git hook run test-hook -- arg "u ments" 2>actual &&
|
|
|
|
test_cmp expect actual
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'git hook run -- out-of-repo runs excluded' '
|
2022-03-17 10:13:06 +00:00
|
|
|
test_hook test-hook <<-EOF &&
|
2021-12-22 03:59:27 +00:00
|
|
|
echo Test hook
|
|
|
|
EOF
|
|
|
|
|
|
|
|
nongit test_must_fail git hook run test-hook
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'git -c core.hooksPath=<PATH> hook run' '
|
|
|
|
mkdir my-hooks &&
|
|
|
|
write_script my-hooks/test-hook <<-\EOF &&
|
2022-10-29 02:59:45 +00:00
|
|
|
echo Hook ran $1
|
2021-12-22 03:59:27 +00:00
|
|
|
EOF
|
|
|
|
|
|
|
|
cat >expect <<-\EOF &&
|
|
|
|
Test hook
|
|
|
|
Hook ran one
|
|
|
|
Hook ran two
|
|
|
|
Hook ran three
|
|
|
|
Hook ran four
|
|
|
|
EOF
|
|
|
|
|
2022-03-17 10:13:06 +00:00
|
|
|
test_hook test-hook <<-EOF &&
|
|
|
|
echo Test hook
|
|
|
|
EOF
|
|
|
|
|
2021-12-22 03:59:27 +00:00
|
|
|
# Test various ways of specifying the path. See also
|
|
|
|
# t1350-config-hooks-path.sh
|
|
|
|
>actual &&
|
|
|
|
git hook run test-hook -- ignored 2>>actual &&
|
|
|
|
git -c core.hooksPath=my-hooks hook run test-hook -- one 2>>actual &&
|
|
|
|
git -c core.hooksPath=my-hooks/ hook run test-hook -- two 2>>actual &&
|
|
|
|
git -c core.hooksPath="$PWD/my-hooks" hook run test-hook -- three 2>>actual &&
|
|
|
|
git -c core.hooksPath="$PWD/my-hooks/" hook run test-hook -- four 2>>actual &&
|
|
|
|
test_cmp expect actual
|
|
|
|
'
|
|
|
|
|
2022-06-07 08:48:20 +00:00
|
|
|
test_hook_tty () {
|
|
|
|
cat >expect <<-\EOF
|
|
|
|
STDOUT TTY
|
|
|
|
STDERR TTY
|
|
|
|
EOF
|
|
|
|
|
|
|
|
test_when_finished "rm -rf repo" &&
|
|
|
|
git init repo &&
|
|
|
|
|
|
|
|
test_commit -C repo A &&
|
|
|
|
test_commit -C repo B &&
|
|
|
|
git -C repo reset --soft HEAD^ &&
|
|
|
|
|
|
|
|
test_hook -C repo pre-commit <<-EOF &&
|
|
|
|
test -t 1 && echo STDOUT TTY >>actual || echo STDOUT NO TTY >>actual &&
|
|
|
|
test -t 2 && echo STDERR TTY >>actual || echo STDERR NO TTY >>actual
|
|
|
|
EOF
|
|
|
|
|
|
|
|
test_terminal git -C repo "$@" &&
|
|
|
|
test_cmp expect repo/actual
|
|
|
|
}
|
|
|
|
|
|
|
|
test_expect_success TTY 'git hook run: stdout and stderr are connected to a TTY' '
|
|
|
|
test_hook_tty hook run pre-commit
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success TTY 'git commit: stdout and stderr are connected to a TTY' '
|
|
|
|
test_hook_tty commit -m"B.new"
|
|
|
|
'
|
|
|
|
|
2022-08-05 14:15:33 +00:00
|
|
|
test_expect_success 'git hook run a hook with a bad shebang' '
|
|
|
|
test_when_finished "rm -rf bad-hooks" &&
|
|
|
|
mkdir bad-hooks &&
|
|
|
|
write_script bad-hooks/test-hook "/bad/path/no/spaces" </dev/null &&
|
|
|
|
|
|
|
|
test_expect_code 1 git \
|
|
|
|
-c core.hooksPath=bad-hooks \
|
|
|
|
hook run test-hook >out 2>err &&
|
|
|
|
test_must_be_empty out &&
|
2023-06-10 14:51:12 +00:00
|
|
|
|
|
|
|
# TODO: We should emit the same (or at least a more similar)
|
|
|
|
# error on MINGW (essentially Git for Windows) and all other
|
|
|
|
# platforms.. See the OS-specific code in start_command()
|
2023-06-10 14:51:21 +00:00
|
|
|
grep -E "^(error|fatal): cannot (exec|spawn) .*bad-hooks/test-hook" err
|
2022-08-05 14:15:33 +00:00
|
|
|
'
|
|
|
|
|
2023-02-08 19:21:15 +00:00
|
|
|
test_expect_success 'stdin to hooks' '
|
|
|
|
write_script .git/hooks/test-hook <<-\EOF &&
|
|
|
|
echo BEGIN stdin
|
|
|
|
cat
|
|
|
|
echo END stdin
|
|
|
|
EOF
|
|
|
|
|
|
|
|
cat >expect <<-EOF &&
|
|
|
|
BEGIN stdin
|
|
|
|
hello
|
|
|
|
END stdin
|
|
|
|
EOF
|
|
|
|
|
|
|
|
echo hello >input &&
|
|
|
|
git hook run --to-stdin=input test-hook 2>actual &&
|
|
|
|
test_cmp expect actual
|
|
|
|
'
|
|
|
|
|
core.hooksPath: add some protection while cloning
Quite frequently, when vulnerabilities were found in Git's (quite
complex) clone machinery, a relatively common way to escalate the
severity was to trick Git into running a hook which is actually a script
that has just been laid on disk as part of that clone. This constitutes
a Remote Code Execution vulnerability, the highest severity observed in
Git's vulnerabilities so far.
Some previously-fixed vulnerabilities allowed malicious repositories to
be crafted such that Git would check out files not in the worktree, but
in, say, a submodule's `<git>/hooks/` directory.
A vulnerability that "merely" allows to modify the Git config would
allow a related attack vector, to manipulate Git into looking in the
worktree for hooks, e.g. redirecting the location where Git looks for
hooks, via setting `core.hooksPath` (which would be classified as
CWE-427: Uncontrolled Search Path Element and CWE-114: Process Control,
for more details see https://cwe.mitre.org/data/definitions/427.html and
https://cwe.mitre.org/data/definitions/114.html).
To prevent that attack vector, let's error out and complain loudly if an
active `core.hooksPath` configuration is seen in the repository-local
Git config during a `git clone`.
There is one caveat: This changes Git's behavior in a slightly
backwards-incompatible manner. While it is probably a rare scenario (if
it exists at all) to configure `core.hooksPath` via a config in the Git
templates, it _is_ conceivable that some valid setup requires this to
work. In the hopefully very unlikely case that a user runs into this,
there is an escape hatch: set the `GIT_CLONE_PROTECTION_ACTIVE=false`
environment variable. Obviously, this should be done only with utmost
caution.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2024-03-30 18:12:50 +00:00
|
|
|
test_expect_success 'clone protections' '
|
|
|
|
test_config core.hooksPath "$(pwd)/my-hooks" &&
|
|
|
|
mkdir -p my-hooks &&
|
|
|
|
write_script my-hooks/test-hook <<-\EOF &&
|
|
|
|
echo Hook ran $1
|
|
|
|
EOF
|
|
|
|
|
|
|
|
git hook run test-hook 2>err &&
|
2024-04-10 20:04:48 +00:00
|
|
|
test_grep "Hook ran" err &&
|
core.hooksPath: add some protection while cloning
Quite frequently, when vulnerabilities were found in Git's (quite
complex) clone machinery, a relatively common way to escalate the
severity was to trick Git into running a hook which is actually a script
that has just been laid on disk as part of that clone. This constitutes
a Remote Code Execution vulnerability, the highest severity observed in
Git's vulnerabilities so far.
Some previously-fixed vulnerabilities allowed malicious repositories to
be crafted such that Git would check out files not in the worktree, but
in, say, a submodule's `<git>/hooks/` directory.
A vulnerability that "merely" allows to modify the Git config would
allow a related attack vector, to manipulate Git into looking in the
worktree for hooks, e.g. redirecting the location where Git looks for
hooks, via setting `core.hooksPath` (which would be classified as
CWE-427: Uncontrolled Search Path Element and CWE-114: Process Control,
for more details see https://cwe.mitre.org/data/definitions/427.html and
https://cwe.mitre.org/data/definitions/114.html).
To prevent that attack vector, let's error out and complain loudly if an
active `core.hooksPath` configuration is seen in the repository-local
Git config during a `git clone`.
There is one caveat: This changes Git's behavior in a slightly
backwards-incompatible manner. While it is probably a rare scenario (if
it exists at all) to configure `core.hooksPath` via a config in the Git
templates, it _is_ conceivable that some valid setup requires this to
work. In the hopefully very unlikely case that a user runs into this,
there is an escape hatch: set the `GIT_CLONE_PROTECTION_ACTIVE=false`
environment variable. Obviously, this should be done only with utmost
caution.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2024-03-30 18:12:50 +00:00
|
|
|
test_must_fail env GIT_CLONE_PROTECTION_ACTIVE=true \
|
|
|
|
git hook run test-hook 2>err &&
|
2024-04-10 20:04:48 +00:00
|
|
|
test_grep "active .core.hooksPath" err &&
|
|
|
|
test_grep ! "Hook ran" err
|
core.hooksPath: add some protection while cloning
Quite frequently, when vulnerabilities were found in Git's (quite
complex) clone machinery, a relatively common way to escalate the
severity was to trick Git into running a hook which is actually a script
that has just been laid on disk as part of that clone. This constitutes
a Remote Code Execution vulnerability, the highest severity observed in
Git's vulnerabilities so far.
Some previously-fixed vulnerabilities allowed malicious repositories to
be crafted such that Git would check out files not in the worktree, but
in, say, a submodule's `<git>/hooks/` directory.
A vulnerability that "merely" allows to modify the Git config would
allow a related attack vector, to manipulate Git into looking in the
worktree for hooks, e.g. redirecting the location where Git looks for
hooks, via setting `core.hooksPath` (which would be classified as
CWE-427: Uncontrolled Search Path Element and CWE-114: Process Control,
for more details see https://cwe.mitre.org/data/definitions/427.html and
https://cwe.mitre.org/data/definitions/114.html).
To prevent that attack vector, let's error out and complain loudly if an
active `core.hooksPath` configuration is seen in the repository-local
Git config during a `git clone`.
There is one caveat: This changes Git's behavior in a slightly
backwards-incompatible manner. While it is probably a rare scenario (if
it exists at all) to configure `core.hooksPath` via a config in the Git
templates, it _is_ conceivable that some valid setup requires this to
work. In the hopefully very unlikely case that a user runs into this,
there is an escape hatch: set the `GIT_CLONE_PROTECTION_ACTIVE=false`
environment variable. Obviously, this should be done only with utmost
caution.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2024-03-30 18:12:50 +00:00
|
|
|
'
|
|
|
|
|
2021-12-22 03:59:27 +00:00
|
|
|
test_done
|