#!/bin/sh

test_description='paths written by git-apply cannot escape the working tree'

TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh

# tests will try to write to ../foo, and we do not
# want them to escape the trash directory when they
# fail
test_expect_success 'bump git repo one level down' '
	mkdir inside &&
	mv .git inside/ &&
	cd inside
'

# $1 = name of file
# $2 = current path to file (if different)
mkpatch_add () {
	rm -f "${2:-$1}" &&
	cat <<-EOF
	diff --git a/$1 b/$1
	new file mode 100644
	index 0000000..53c74cd
	--- /dev/null
	+++ b/$1
	@@ -0,0 +1 @@
	+evil
	EOF
}

mkpatch_del () {
	echo evil >"${2:-$1}" &&
	cat <<-EOF
	diff --git a/$1 b/$1
	deleted file mode 100644
	index 53c74cd..0000000
	--- a/$1
	+++ /dev/null
	@@ -1 +0,0 @@
	-evil
	EOF
}

# $1 = name of file
# $2 = content of symlink
mkpatch_symlink () {
	rm -f "$1" &&
	cat <<-EOF
	diff --git a/$1 b/$1
	new file mode 120000
	index 0000000..$(printf "%s" "$2" | git hash-object --stdin)
	--- /dev/null
	+++ b/$1
	@@ -0,0 +1 @@
	+$2
	\ No newline at end of file
	EOF
}

test_expect_success 'cannot create file containing ..' '
	mkpatch_add ../foo >patch &&
	test_must_fail git apply patch &&
	test_path_is_missing ../foo
'

test_expect_success 'can create file containing .. with --unsafe-paths' '
	mkpatch_add ../foo >patch &&
	git apply --unsafe-paths patch &&
	test_path_is_file ../foo
'

test_expect_success  'cannot create file containing .. (index)' '
	mkpatch_add ../foo >patch &&
	test_must_fail git apply --index patch &&
	test_path_is_missing ../foo
'

test_expect_success  'cannot create file containing .. with --unsafe-paths (index)' '
	mkpatch_add ../foo >patch &&
	test_must_fail git apply --index --unsafe-paths patch &&
	test_path_is_missing ../foo
'

test_expect_success 'cannot delete file containing ..' '
	mkpatch_del ../foo >patch &&
	test_must_fail git apply patch &&
	test_path_is_file ../foo
'

test_expect_success 'can delete file containing .. with --unsafe-paths' '
	mkpatch_del ../foo >patch &&
	git apply --unsafe-paths patch &&
	test_path_is_missing ../foo
'

test_expect_success 'cannot delete file containing .. (index)' '
	mkpatch_del ../foo >patch &&
	test_must_fail git apply --index patch &&
	test_path_is_file ../foo
'

test_expect_success SYMLINKS 'symlink escape via ..' '
	{
		mkpatch_symlink tmp .. &&
		mkpatch_add tmp/foo ../foo
	} >patch &&
	test_must_fail git apply patch &&
	test_path_is_missing tmp &&
	test_path_is_missing ../foo
'

test_expect_success SYMLINKS 'symlink escape via .. (index)' '
	{
		mkpatch_symlink tmp .. &&
		mkpatch_add tmp/foo ../foo
	} >patch &&
	test_must_fail git apply --index patch &&
	test_path_is_missing tmp &&
	test_path_is_missing ../foo
'

test_expect_success SYMLINKS 'symlink escape via absolute path' '
	{
		mkpatch_symlink tmp "$(pwd)" &&
		mkpatch_add tmp/foo ../foo
	} >patch &&
	test_must_fail git apply patch &&
	test_path_is_missing tmp &&
	test_path_is_missing ../foo
'

test_expect_success SYMLINKS 'symlink escape via absolute path (index)' '
	{
		mkpatch_symlink tmp "$(pwd)" &&
		mkpatch_add tmp/foo ../foo
	} >patch &&
	test_must_fail git apply --index patch &&
	test_path_is_missing tmp &&
	test_path_is_missing ../foo
'

test_done
