Commit c7d20a3f8da31a213c3830e6ca9de6d3b0c728bb

Stefan Sperling 2019-07-30T17:46:15

forbid editing the history of branches outside of "refs/heads"

diff --git a/got/got.1 b/got/got.1
index a51741e..ee870b0 100644
--- a/got/got.1
+++ b/got/got.1
@@ -769,6 +769,9 @@ when the histedit operation continues.
 .Pp
 .Cm got histedit
 will refuse to run if certain preconditions are not met.
+If the work tree's current branch is not in the
+.Dq refs/heads/
+reference namespace, the history of the branch may not be edited.
 If the work tree contains multiple base commits it must first be updated
 to a single base commit with
 .Cm got update .
diff --git a/got/got.c b/got/got.c
index e2cf661..5356c71 100644
--- a/got/got.c
+++ b/got/got.c
@@ -4956,6 +4956,13 @@ cmd_histedit(int argc, char *argv[])
 		if (error != NULL)
 			goto done;
 
+		if (strncmp(got_ref_get_name(branch), "refs/heads/", 11) != 0) {
+			error = got_error_msg(GOT_ERR_COMMIT_BRANCH,
+			    "will not edit commit history of a branch outside "
+			    "the \"refs/heads/\" reference namespace");
+			goto done;
+		}
+
 		error = got_ref_resolve(&head_commit_id, repo, branch);
 		got_ref_close(branch);
 		branch = NULL;
diff --git a/regress/cmdline/histedit.sh b/regress/cmdline/histedit.sh
index 4c72997..a859ac4 100755
--- a/regress/cmdline/histedit.sh
+++ b/regress/cmdline/histedit.sh
@@ -1039,6 +1039,62 @@ function test_histedit_path_prefix_edit {
 	test_done "$testroot" "$ret"
 }
 
+function test_histedit_outside_refs_heads {
+	local testroot=`test_init histedit_outside_refs_heads`
+	local commit1=`git_show_head $testroot/repo`
+
+	got checkout $testroot/repo $testroot/wt > /dev/null
+	ret="$?"
+	if [ "$ret" != "0" ]; then
+		echo "got checkout failed unexpectedly"
+		test_done "$testroot" "$ret"
+		return 1
+	fi
+
+	echo "modified alpha" > $testroot/wt/alpha
+
+	(cd $testroot/wt && got commit -m 'change alpha' \
+		> $testroot/stdout 2> $testroot/stderr)
+	ret="$?"
+	if [ "$ret" != "0" ]; then
+		echo "got commit failed unexpectedly" >&2
+		test_done "$testroot" "1"
+		return 1
+	fi
+	local commit2=`git_show_head $testroot/repo`
+
+	got ref -r $testroot/repo refs/remotes/origin/master master
+	ret="$?"
+	if [ "$ret" != "0" ]; then
+		echo "got ref failed unexpectedly" >&2
+		test_done "$testroot" "1"
+		return 1
+	fi
+
+	(cd $testroot/wt && got update -b origin/master -c $commit1 >/dev/null)
+	ret="$?"
+	if [ "$ret" != "0" ]; then
+		echo "got update failed unexpectedly"
+		test_done "$testroot" "$ret"
+		return 1
+	fi
+
+	echo "edit $commit2" > $testroot/histedit-script
+	(cd $testroot/wt && got histedit -F $testroot/histedit-script \
+		2> $testroot/stderr)
+
+	echo -n "got: will not edit commit history of a branch outside the " \
+		> $testroot/stderr.expected
+	echo '"refs/heads/" reference namespace' \
+		>> $testroot/stderr.expected
+	cmp -s $testroot/stderr.expected $testroot/stderr
+	ret="$?"
+	if [ "$ret" != "0" ]; then
+		diff -u $testroot/stderr.expected $testroot/stderr
+	fi
+	test_done "$testroot" "$ret"
+}
+
 run_test test_histedit_no_op
 run_test test_histedit_swap
 run_test test_histedit_drop
@@ -1049,3 +1105,4 @@ run_test test_histedit_missing_commit
 run_test test_histedit_abort
 run_test test_histedit_path_prefix_drop
 run_test test_histedit_path_prefix_edit
+run_test test_histedit_outside_refs_heads