Cover absent/no-distro bash.exe in hooks "not from cwd" test · gitpython-developers/GitPython@a42ea0a (original) (raw)

`@@ -41,7 +41,14 @@

`

41

41

`from git.objects import Blob

`

42

42

`from git.util import Actor, cwd, hex_to_bin, rmtree

`

43

43

`from gitdb.base import IStream

`

44

``

`-

from test.lib import TestBase, fixture, fixture_path, with_rw_directory, with_rw_repo

`

``

44

`+

from test.lib import (

`

``

45

`+

TestBase,

`

``

46

`+

VirtualEnvironment,

`

``

47

`+

fixture,

`

``

48

`+

fixture_path,

`

``

49

`+

with_rw_directory,

`

``

50

`+

with_rw_repo,

`

``

51

`+

)

`

45

52

``

46

53

`HOOKS_SHEBANG = "#!/usr/bin/env sh\n"

`

47

54

``

`@@ -1016,36 +1023,46 @@ def test_run_commit_hook(self, rw_repo):

`

1016

1023

`output = Path(rw_repo.git_dir, "output.txt").read_text(encoding="utf-8")

`

1017

1024

`self.assertEqual(output, "ran fake hook\n")

`

1018

1025

``

1019

``

`-

FIXME: Figure out a way to make this test also work with Absent and WslNoDistro.

`

1020

``

`-

@pytest.mark.xfail(

`

1021

``

`-

type(_win_bash_status) is WinBashStatus.WslNoDistro,

`

1022

``

`-

reason="Currently uses the bash.exe of WSL, even with no WSL distro installed",

`

1023

``

`-

raises=HookExecutionError,

`

1024

``

`-

)

`

1025

1026

`@ddt.data((False,), (True,))

`

1026

1027

`@with_rw_directory

`

1027

1028

`def test_hook_uses_shell_not_from_cwd(self, rw_dir, case):

`

1028

1029

` (chdir_to_repo,) = case

`

1029

1030

``

``

1031

`+

shell_name = "bash.exe" if os.name == "nt" else "sh"

`

``

1032

`+

maybe_chdir = cwd(rw_dir) if chdir_to_repo else contextlib.nullcontext()

`

1030

1033

`repo = Repo.init(rw_dir)

`

1031

``

`-

_make_hook(repo.git_dir, "fake-hook", "echo 'ran fake hook' >output.txt")

`

1032

1034

``

1033

``

`-

if os.name == "nt":

`

1034

``

`-

Copy an actual binary that is not bash.

`

1035

``

`-

other_exe_path = Path(os.environ["SystemRoot"], "system32", "hostname.exe")

`

1036

``

`-

impostor_path = Path(rw_dir, "bash.exe")

`

1037

``

`-

shutil.copy(other_exe_path, impostor_path)

`

``

1035

`+

We need an impostor shell that works on Windows and that can be distinguished

`

``

1036

`+

from the real bash.exe. But even if the real bash.exe is absent or unusable,

`

``

1037

`+

we should verify that the impostor is not run. So the impostor needs a clear

`

``

1038

`+

side effect (unlike in TestGit.test_it_executes_git_not_from_cwd). Popen on

`

``

1039

`+

Windows uses CreateProcessW, which disregards PATHEXT; the impostor may need

`

``

1040

`+

to be a binary executable to ensure the vulnerability is found if present. No

`

``

1041

`+

compiler need exist, shipping a binary in the test suite may target the wrong

`

``

1042

`+

architecture, and generating one in a bespoke way may cause virus scanners to

`

``

1043

`+

give a false positive. So we use a Bash/Python polyglot for the hook and use

`

``

1044

`+

the Python interpreter itself as the bash.exe impostor. But an interpreter

`

``

1045

`+

from a venv may not run outside of it, and a global interpreter won't run from

`

``

1046

`+

a different location if it was installed from the Microsoft Store. So we make

`

``

1047

`+

a new venv in rw_dir and use its interpreter.

`

``

1048

`+

venv = VirtualEnvironment(rw_dir, with_pip=False)

`

``

1049

`+

shutil.copy(venv.python, Path(rw_dir, shell_name))

`

``

1050

`+

shutil.copy(fixture_path("polyglot"), hook_path("polyglot", repo.git_dir))

`

``

1051

`+

payload = Path(rw_dir, "payload.txt")

`

``

1052

+

``

1053

`+

if type(_win_bash_status) in {WinBashStatus.Absent, WinBashStatus.WslNoDistro}:

`

``

1054

`+

The real shell can't run, but the impostor should still not be used.

`

``

1055

`+

with self.assertRaises(HookExecutionError):

`

``

1056

`+

with maybe_chdir:

`

``

1057

`+

run_commit_hook("polyglot", repo.index)

`

``

1058

`+

self.assertFalse(payload.exists())

`

1038

1059

`else:

`

1039

``

`-

Create a shell script that doesn't do anything.

`

1040

``

`-

impostor_path = Path(rw_dir, "sh")

`

1041

``

`-

impostor_path.write_text("#!/bin/sh\n", encoding="utf-8")

`

1042

``

`-

os.chmod(impostor_path, 0o755)

`

1043

``

-

1044

``

`-

with cwd(rw_dir) if chdir_to_repo else contextlib.nullcontext():

`

1045

``

`-

run_commit_hook("fake-hook", repo.index)

`

1046

``

-

1047

``

`-

output = Path(rw_dir, "output.txt").read_text(encoding="utf-8")

`

1048

``

`-

self.assertEqual(output, "ran fake hook\n")

`

``

1060

`+

The real shell should run, and not the impostor.

`

``

1061

`+

with maybe_chdir:

`

``

1062

`+

run_commit_hook("polyglot", repo.index)

`

``

1063

`+

self.assertFalse(payload.exists())

`

``

1064

`+

output = Path(rw_dir, "output.txt").read_text(encoding="utf-8")

`

``

1065

`+

self.assertEqual(output, "Ran intended hook.\n")

`

1049

1066

``

1050

1067

`@pytest.mark.xfail(

`

1051

1068

`type(_win_bash_status) is WinBashStatus.Absent,

`