Commit d5017a14284447c289dd04cae1a310dc34aa562c

Edward Thomson 2019-11-01T07:00:16

Merge pull request #5289 from libgit2/cmn/create-with-signature-verification commit: verify objects exist in git_commit_with_signature

diff --git a/src/commit.c b/src/commit.c
index 20e0b8a..aca65ff 100644
--- a/src/commit.c
+++ b/src/commit.c
@@ -878,6 +878,14 @@ static void format_header_field(git_buf *out, const char *field, const char *con
 	git_buf_putc(out, '\n');
 }
 
+static const git_oid *commit_parent_from_commit(size_t n, void *payload)
+{
+	const git_commit *commit = (const git_commit *) payload;
+
+	return git_array_get(commit->parent_ids, n);
+
+}
+
 int git_commit_create_with_signature(
 	git_oid *out,
 	git_repository *repo,
@@ -890,12 +898,26 @@ int git_commit_create_with_signature(
 	const char *field;
 	const char *header_end;
 	git_buf commit = GIT_BUF_INIT;
+	git_commit *parsed;
+	git_array_oid_t parents = GIT_ARRAY_INIT;
 
-	/* We start by identifying the end of the commit header */
+	/* The first step is to verify that all the tree and parents exist */
+	parsed = git__calloc(1, sizeof(git_commit));
+	GIT_ERROR_CHECK_ALLOC(parsed);
+	if ((error = commit_parse(parsed, commit_content, strlen(commit_content), 0)) < 0)
+		goto cleanup;
+
+	if ((error = validate_tree_and_parents(&parents, repo, &parsed->tree_id, commit_parent_from_commit, parsed, NULL, true)) < 0)
+		goto cleanup;
+
+	git_array_clear(parents);
+
+	/* Then we start appending by identifying the end of the commit header */
 	header_end = strstr(commit_content, "\n\n");
 	if (!header_end) {
 		git_error_set(GIT_ERROR_INVALID, "malformed commit contents");
-		return -1;
+		error = -1;
+		goto cleanup;
 	}
 
 	/* The header ends after the first LF */
@@ -919,6 +941,7 @@ int git_commit_create_with_signature(
 		goto cleanup;
 
 cleanup:
+	git_commit__free(parsed);
 	git_buf_dispose(&commit);
 	return error;
 }
diff --git a/tests/commit/write.c b/tests/commit/write.c
index d829c97..2c22785 100644
--- a/tests/commit/write.c
+++ b/tests/commit/write.c
@@ -299,19 +299,43 @@ void test_commit_write__can_validate_objects(void)
 	cl_git_fail(create_commit_from_ids(&commit_id, &tree_id, &parent_id));
 }
 
-void test_commit_write__attach_singleline_signature(void)
+void test_commit_write__attach_signature_checks_objects(void)
 {
 	const char *sig = "magic word: pretty please";
+	const char *badtree =  "tree 6b79e22d69bf46e289df0345a14ca059dfc9bdf6\n\
+parent 34734e478d6cf50c27c9d69026d93974d052c454\n\
+author Ben Burkert <ben@benburkert.com> 1358451456 -0800\n\
+committer Ben Burkert <ben@benburkert.com> 1358451456 -0800\n\
+\n\
+a simple commit which does not work\n";
 
-	const char *data =  "tree 6b79e22d69bf46e289df0345a14ca059dfc9bdf6\n\
+	const char *badparent =  "tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904\n\
 parent 34734e478d6cf50c27c9d69026d93974d052c454\n\
 author Ben Burkert <ben@benburkert.com> 1358451456 -0800\n\
 committer Ben Burkert <ben@benburkert.com> 1358451456 -0800\n\
 \n\
+a simple commit which does not work\n";
+
+	git_oid id;
+
+	cl_git_fail_with(-1, git_commit_create_with_signature(&id, g_repo, badtree, sig, "magicsig"));
+	cl_git_fail_with(-1, git_commit_create_with_signature(&id, g_repo, badparent, sig, "magicsig"));
+
+}
+
+void test_commit_write__attach_singleline_signature(void)
+{
+	const char *sig = "magic word: pretty please";
+
+	const char *data =  "tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904\n\
+parent 8496071c1b46c854b31185ea97743be6a8774479\n\
+author Ben Burkert <ben@benburkert.com> 1358451456 -0800\n\
+committer Ben Burkert <ben@benburkert.com> 1358451456 -0800\n\
+\n\
 a simple commit which works\n";
 
-	const char *complete =  "tree 6b79e22d69bf46e289df0345a14ca059dfc9bdf6\n\
-parent 34734e478d6cf50c27c9d69026d93974d052c454\n\
+	const char *complete =  "tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904\n\
+parent 8496071c1b46c854b31185ea97743be6a8774479\n\
 author Ben Burkert <ben@benburkert.com> 1358451456 -0800\n\
 committer Ben Burkert <ben@benburkert.com> 1358451456 -0800\n\
 magicsig magic word: pretty please\n\
@@ -352,15 +376,15 @@ cpxtDQQMGYFpXK/71stq\n\
 =ozeK\n\
 -----END PGP SIGNATURE-----";
 
-	const char *data =  "tree 6b79e22d69bf46e289df0345a14ca059dfc9bdf6\n\
-parent 34734e478d6cf50c27c9d69026d93974d052c454\n\
+	const char *data =  "tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904\n\
+parent 8496071c1b46c854b31185ea97743be6a8774479\n\
 author Ben Burkert <ben@benburkert.com> 1358451456 -0800\n\
 committer Ben Burkert <ben@benburkert.com> 1358451456 -0800\n\
 \n\
 a simple commit which works\n";
 
-const char *complete = "tree 6b79e22d69bf46e289df0345a14ca059dfc9bdf6\n\
-parent 34734e478d6cf50c27c9d69026d93974d052c454\n\
+const char *complete = "tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904\n\
+parent 8496071c1b46c854b31185ea97743be6a8774479\n\
 author Ben Burkert <ben@benburkert.com> 1358451456 -0800\n\
 committer Ben Burkert <ben@benburkert.com> 1358451456 -0800\n\
 gpgsig -----BEGIN PGP SIGNATURE-----\n\