verify-commit: scriptable commit signature verification
Commit signatures can be verified using "git show -s --show-signature" or the "%G?" pretty format and parsing the output, which is well suited for user inspection, but not for scripting. Provide a command "verify-commit" which is analogous to "verify-tag": It returns 0 for good signatures and non-zero otherwise, has the gpg output on stderr and (optionally) the commit object on stdout, sans the signature, just like "verify-tag" does. Signed-off-by: Michael J Gruber <git@drmicha.warpmail.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>maint
							parent
							
								
									71c214c840
								
							
						
					
					
						commit
						d07b00b7f3
					
				|  | @ -0,0 +1,28 @@ | |||
| git-verify-commit(1) | ||||
| ==================== | ||||
|  | ||||
| NAME | ||||
| ---- | ||||
| git-verify-commit - Check the GPG signature of commits | ||||
|  | ||||
| SYNOPSIS | ||||
| -------- | ||||
| [verse] | ||||
| 'git verify-commit' <commit>... | ||||
|  | ||||
| DESCRIPTION | ||||
| ----------- | ||||
| Validates the gpg signature created by 'git commit -S'. | ||||
|  | ||||
| OPTIONS | ||||
| ------- | ||||
| -v:: | ||||
| --verbose:: | ||||
| 	Print the contents of the commit object before validating it. | ||||
|  | ||||
| <commit>...:: | ||||
| 	SHA-1 identifiers of Git commit objects. | ||||
|  | ||||
| GIT | ||||
| --- | ||||
| Part of the linkgit:git[1] suite | ||||
							
								
								
									
										1
									
								
								Makefile
								
								
								
								
							
							
						
						
									
										1
									
								
								Makefile
								
								
								
								
							|  | @ -999,6 +999,7 @@ BUILTIN_OBJS += builtin/update-ref.o | |||
| BUILTIN_OBJS += builtin/update-server-info.o | ||||
| BUILTIN_OBJS += builtin/upload-archive.o | ||||
| BUILTIN_OBJS += builtin/var.o | ||||
| BUILTIN_OBJS += builtin/verify-commit.o | ||||
| BUILTIN_OBJS += builtin/verify-pack.o | ||||
| BUILTIN_OBJS += builtin/verify-tag.o | ||||
| BUILTIN_OBJS += builtin/write-tree.o | ||||
|  |  | |||
|  | @ -128,6 +128,7 @@ extern int cmd_update_server_info(int argc, const char **argv, const char *prefi | |||
| extern int cmd_upload_archive(int argc, const char **argv, const char *prefix); | ||||
| extern int cmd_upload_archive_writer(int argc, const char **argv, const char *prefix); | ||||
| extern int cmd_var(int argc, const char **argv, const char *prefix); | ||||
| extern int cmd_verify_commit(int argc, const char **argv, const char *prefix); | ||||
| extern int cmd_verify_tag(int argc, const char **argv, const char *prefix); | ||||
| extern int cmd_version(int argc, const char **argv, const char *prefix); | ||||
| extern int cmd_whatchanged(int argc, const char **argv, const char *prefix); | ||||
|  |  | |||
|  | @ -0,0 +1,93 @@ | |||
| /* | ||||
|  * Builtin "git commit-commit" | ||||
|  * | ||||
|  * Copyright (c) 2014 Michael J Gruber <git@drmicha.warpmail.net> | ||||
|  * | ||||
|  * Based on git-verify-tag | ||||
|  */ | ||||
| #include "cache.h" | ||||
| #include "builtin.h" | ||||
| #include "commit.h" | ||||
| #include "run-command.h" | ||||
| #include <signal.h> | ||||
| #include "parse-options.h" | ||||
| #include "gpg-interface.h" | ||||
|  | ||||
| static const char * const verify_commit_usage[] = { | ||||
| 		N_("git verify-commit [-v|--verbose] <commit>..."), | ||||
| 		NULL | ||||
| }; | ||||
|  | ||||
| static int run_gpg_verify(const unsigned char *sha1, const char *buf, unsigned long size, int verbose) | ||||
| { | ||||
| 	struct signature_check signature_check; | ||||
|  | ||||
| 	memset(&signature_check, 0, sizeof(signature_check)); | ||||
|  | ||||
| 	check_commit_signature(lookup_commit(sha1), &signature_check); | ||||
|  | ||||
| 	if (verbose && signature_check.payload) | ||||
| 		fputs(signature_check.payload, stdout); | ||||
|  | ||||
| 	if (signature_check.gpg_output) | ||||
| 		fputs(signature_check.gpg_output, stderr); | ||||
|  | ||||
| 	signature_check_clear(&signature_check); | ||||
| 	return signature_check.result != 'G'; | ||||
| } | ||||
|  | ||||
| static int verify_commit(const char *name, int verbose) | ||||
| { | ||||
| 	enum object_type type; | ||||
| 	unsigned char sha1[20]; | ||||
| 	char *buf; | ||||
| 	unsigned long size; | ||||
| 	int ret; | ||||
|  | ||||
| 	if (get_sha1(name, sha1)) | ||||
| 		return error("commit '%s' not found.", name); | ||||
|  | ||||
| 	buf = read_sha1_file(sha1, &type, &size); | ||||
| 	if (!buf) | ||||
| 		return error("%s: unable to read file.", name); | ||||
| 	if (type != OBJ_COMMIT) | ||||
| 		return error("%s: cannot verify a non-commit object of type %s.", | ||||
| 				name, typename(type)); | ||||
|  | ||||
| 	ret = run_gpg_verify(sha1, buf, size, verbose); | ||||
|  | ||||
| 	free(buf); | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| static int git_verify_commit_config(const char *var, const char *value, void *cb) | ||||
| { | ||||
| 	int status = git_gpg_config(var, value, cb); | ||||
| 	if (status) | ||||
| 		return status; | ||||
| 	return git_default_config(var, value, cb); | ||||
| } | ||||
|  | ||||
| int cmd_verify_commit(int argc, const char **argv, const char *prefix) | ||||
| { | ||||
| 	int i = 1, verbose = 0, had_error = 0; | ||||
| 	const struct option verify_commit_options[] = { | ||||
| 		OPT__VERBOSE(&verbose, N_("print commit contents")), | ||||
| 		OPT_END() | ||||
| 	}; | ||||
|  | ||||
| 	git_config(git_verify_commit_config, NULL); | ||||
|  | ||||
| 	argc = parse_options(argc, argv, prefix, verify_commit_options, | ||||
| 			     verify_commit_usage, PARSE_OPT_KEEP_ARGV0); | ||||
| 	if (argc <= i) | ||||
| 		usage_with_options(verify_commit_usage, verify_commit_options); | ||||
|  | ||||
| 	/* sometimes the program was terminated because this signal | ||||
| 	 * was received in the process of writing the gpg input: */ | ||||
| 	signal(SIGPIPE, SIG_IGN); | ||||
| 	while (i < argc) | ||||
| 		if (verify_commit(argv[i++], verbose)) | ||||
| 			had_error = 1; | ||||
| 	return had_error; | ||||
| } | ||||
|  | @ -132,6 +132,7 @@ git-update-server-info                  synchingrepositories | |||
| git-upload-archive                      synchelpers | ||||
| git-upload-pack                         synchelpers | ||||
| git-var                                 plumbinginterrogators | ||||
| git-verify-commit                       ancillaryinterrogators | ||||
| git-verify-pack                         plumbinginterrogators | ||||
| git-verify-tag                          ancillaryinterrogators | ||||
| gitweb                                  ancillaryinterrogators | ||||
|  |  | |||
							
								
								
									
										1
									
								
								git.c
								
								
								
								
							
							
						
						
									
										1
									
								
								git.c
								
								
								
								
							|  | @ -441,6 +441,7 @@ static struct cmd_struct commands[] = { | |||
| 	{ "upload-archive", cmd_upload_archive }, | ||||
| 	{ "upload-archive--writer", cmd_upload_archive_writer }, | ||||
| 	{ "var", cmd_var, RUN_SETUP_GENTLY }, | ||||
| 	{ "verify-commit", cmd_verify_commit, RUN_SETUP }, | ||||
| 	{ "verify-pack", cmd_verify_pack }, | ||||
| 	{ "verify-tag", cmd_verify_tag, RUN_SETUP }, | ||||
| 	{ "version", cmd_version }, | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Michael J Gruber
						Michael J Gruber