Commit 3c8a860df4dd1dfe1aad74c884529184b7d932b2

Edward Thomson 2022-07-13T10:19:14

Merge pull request #6348 from lya001/fix-invalid-branch-name Fix creation of branches and tags with invalid names

diff --git a/src/libgit2/branch.c b/src/libgit2/branch.c
index 2e29af9..2dd7d2b 100644
--- a/src/libgit2/branch.c
+++ b/src/libgit2/branch.c
@@ -53,6 +53,17 @@ static int not_a_local_branch(const char *reference_name)
 	return -1;
 }
 
+static bool branch_name_is_valid(const char *branch_name)
+{
+	/*
+	 * Discourage branch name starting with dash,
+	 * https://github.com/git/git/commit/6348624010888b
+	 * and discourage HEAD as branch name,
+	 * https://github.com/git/git/commit/a625b092cc5994
+	 */
+	return branch_name[0] != '-' && git__strcmp(branch_name, "HEAD");
+}
+
 static int create_branch(
 	git_reference **ref_out,
 	git_repository *repository,
@@ -73,8 +84,8 @@ static int create_branch(
 	GIT_ASSERT_ARG(ref_out);
 	GIT_ASSERT_ARG(git_commit_owner(commit) == repository);
 
-	if (!git__strcmp(branch_name, "HEAD")) {
-		git_error_set(GIT_ERROR_REFERENCE, "'HEAD' is not a valid branch name");
+	if (!branch_name_is_valid(branch_name)) {
+		git_error_set(GIT_ERROR_REFERENCE, "'%s' is not a valid branch name", branch_name);
 		error = -1;
 		goto cleanup;
 	}
@@ -797,13 +808,7 @@ int git_branch_name_is_valid(int *valid, const char *name)
 
 	*valid = 0;
 
-	/*
-	 * Discourage branch name starting with dash,
-	 * https://github.com/git/git/commit/6348624010888b
-	 * and discourage HEAD as branch name,
-	 * https://github.com/git/git/commit/a625b092cc5994
-	 */
-	if (!name || name[0] == '-' || !git__strcmp(name, "HEAD"))
+	if (!name || !branch_name_is_valid(name))
 		goto done;
 
 	if ((error = git_str_puts(&ref_name, GIT_REFS_HEADS_DIR)) < 0 ||
diff --git a/src/libgit2/tag.c b/src/libgit2/tag.c
index 5734106..792155a 100644
--- a/src/libgit2/tag.c
+++ b/src/libgit2/tag.c
@@ -244,6 +244,15 @@ on_error:
 	return -1;
 }
 
+static bool tag_name_is_valid(const char *tag_name)
+{
+	/*
+	 * Discourage tag name starting with dash,
+	 * https://github.com/git/git/commit/4f0accd638b8d2
+	 */
+	return tag_name[0] != '-';
+}
+
 static int git_tag_create__internal(
 		git_oid *oid,
 		git_repository *repo,
@@ -269,6 +278,11 @@ static int git_tag_create__internal(
 		return -1;
 	}
 
+	if (!tag_name_is_valid(tag_name)) {
+		git_error_set(GIT_ERROR_TAG, "'%s' is not a valid tag name", tag_name);
+		return -1;
+	}
+
 	error = retrieve_tag_reference_oid(oid, &ref_name, repo, tag_name);
 	if (error < 0 && error != GIT_ENOTFOUND)
 		goto cleanup;
@@ -542,11 +556,7 @@ int git_tag_name_is_valid(int *valid, const char *name)
 
 	*valid = 0;
 
-	/*
-	 * Discourage tag name starting with dash,
-	 * https://github.com/git/git/commit/4f0accd638b8d2
-	 */
-	if (!name || name[0] == '-')
+	if (!name || !tag_name_is_valid(name))
 		goto done;
 
 	if ((error = git_str_puts(&ref_name, GIT_REFS_TAGS_DIR)) < 0 ||
diff --git a/tests/libgit2/object/tag/write.c b/tests/libgit2/object/tag/write.c
index 3c1a989..064f328 100644
--- a/tests/libgit2/object/tag/write.c
+++ b/tests/libgit2/object/tag/write.c
@@ -258,3 +258,22 @@ void test_object_tag_write__creating_an_annotation_does_not_create_a_reference(v
 	create_annotation(&tag_id, "new_tag");
 	cl_git_fail_with(git_reference_lookup(&tag_ref, g_repo, "refs/tags/new_tag"), GIT_ENOTFOUND);
 }
+
+void test_object_tag_write__error_when_create_tag_with_invalid_name(void)
+{
+	git_oid target_id, tag_id;
+	git_signature *tagger;
+	git_object *target;
+
+	git_oid_fromstr(&target_id, tagged_commit);
+	cl_git_pass(git_object_lookup(&target, g_repo, &target_id, GIT_OBJECT_COMMIT));
+	cl_git_pass(git_signature_new(&tagger, tagger_name, tagger_email, 123456789, 60));
+
+	cl_git_fail(
+		git_tag_create(&tag_id, g_repo,
+		  "-dash", target, tagger, tagger_message, 0)
+	);
+
+	git_object_free(target);
+	git_signature_free(tagger);
+}
diff --git a/tests/libgit2/refs/branches/create.c b/tests/libgit2/refs/branches/create.c
index 2fb1166..356bad4 100644
--- a/tests/libgit2/refs/branches/create.c
+++ b/tests/libgit2/refs/branches/create.c
@@ -277,3 +277,11 @@ void test_refs_branches_create__name_vs_namespace_fail(void)
 		branch = NULL;
 	}
 }
+
+void test_refs_branches_create__error_when_create_branch_with_invalid_name(void)
+{
+	retrieve_known_commit(&target, repo);
+
+	cl_git_fail(git_branch_create(&branch, repo, "HEAD", target, 0));
+	cl_git_fail(git_branch_create(&branch, repo, "-dash", target, 0));
+}