git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v2 6/6] verify-commit: add a --summary flag

From
Christian Couder <christian.couder@gmail.com>
Date
May 26, 2025, 10:33 UTC
Message-ID
<20250526103314.1542316-7-christian.couder@gmail.com>
In-Reply-To
<20250526103314.1542316-1-christian.couder@gmail.com>

The current outputs, with `--raw`, `--verbose` or by default, from `git verify-commit` are all quite verbose and do not make it easy to quickly assess signature status.

Let's add a new `--summary` option to `git verify-commit` that prints a concise, one-line summary of the signature verification to standard output.

This compact format is useful for scripts and tools that need to quickly parse signature verification results, while still being human-readable.

Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
---
 Documentation/git-verify-commit.adoc | 17 ++++++++++++++++-
 builtin/verify-commit.c              |  4 +++-
 gpg-interface.c                      | 11 +++++++++++
 gpg-interface.h                      |  6 ++++++
 t/t7510-signed-commit.sh             | 24 ++++++++++++++++++++++++
 t/t7528-signed-commit-ssh.sh         | 28 ++++++++++++++++++++++++++++
 6 files changed, 88 insertions(+), 2 deletions(-)
diff --git a/Documentation/git-verify-commit.adoc b/Documentation/git-verify-commit.adoc
index 6a208a0c2a..fb038ae0cf 100644
--- a/Documentation/git-verify-commit.adoc
+++ b/Documentation/git-verify-commit.adoc
@@ -8,7 +8,7 @@ git-verify-commit - Check the signature of commits
 SYNOPSIS
 --------
 [verse]
-'git verify-commit' [-v | --verbose] [--raw] <commit>...
+'git verify-commit' [-v | --verbose] [--raw] [--summary] <commit>...
 
 DESCRIPTION
 -----------
@@ -38,6 +38,21 @@ OPTIONS
 	error instead of the normal human-readable output. The format
 	of this output is specific to the signature format being used.
 
+--summary::
+	Print a one-line human-readable summary of the signature check
+	to standard output in the format: `STATUS FORMAT ALGORITHM`.
++
+STATUS is the result character (e.g., G, B, E, U, N, ...) shown by the
+"%G?" pretty format specifier. See the "Pretty Formats" section in
+linkgit:git-log[1].
++
+FORMAT indicates the signature format (`openpgp`, `x509`, or `ssh`) or
+`?` if unknown.
++
+ALGORITHM is the hash algorithm used for GPG/GPGSM signatures
+(e.g. `sha1`, `sha256`, ...), or the key type for SSH signatures
+(`RSA`, `ECDSA`, `ED25519`, ...), or `?` if unknown.
+
 -v::
 --verbose::
 	Print the contents of the commit object before validating it.
diff --git a/builtin/verify-commit.c b/builtin/verify-commit.c
index 5f749a30da..54b5b7d360 100644
--- a/builtin/verify-commit.c
+++ b/builtin/verify-commit.c
@@ -14,7 +14,7 @@
 #include "gpg-interface.h"
 
 static const char * const verify_commit_usage[] = {
-		N_("git verify-commit [-v | --verbose] [--raw] <commit>..."),
+		N_("git verify-commit [-v | --verbose] [--raw] [--summary] <commit>..."),
 		NULL
 };
 
@@ -27,6 +27,7 @@ static int run_gpg_verify(struct commit *commit, unsigned flags)
 
 	ret = check_commit_signature(commit, &signature_check);
 	print_signature_buffer(&signature_check, flags);
+	print_signature_summary(&signature_check, flags);
 
 	signature_check_clear(&signature_check);
 	return ret;
@@ -60,6 +61,7 @@ int cmd_verify_commit(int argc,
 	const struct option verify_commit_options[] = {
 		OPT__VERBOSE(&verbose, N_("print commit contents")),
 		OPT_BIT(0, "raw", &flags, N_("print raw gpg status output"), GPG_VERIFY_RAW),
+		OPT_BIT(0, "summary", &flags, N_("print concise signature verification summary"), GPG_VERIFY_SUMMARY),
 		OPT_END()
 	};
 
diff --git a/gpg-interface.c b/gpg-interface.c
index 182e579769..fc198715c4 100644
--- a/gpg-interface.c
+++ b/gpg-interface.c
@@ -153,6 +153,7 @@ void signature_check_clear(struct signature_check *sigc)
 	FREE_AND_NULL(sigc->key);
 	FREE_AND_NULL(sigc->fingerprint);
 	FREE_AND_NULL(sigc->primary_key_fingerprint);
+	FREE_AND_NULL(sigc->format_name);
 	FREE_AND_NULL(sigc->sig_algo);
 }
 
@@ -756,6 +757,8 @@ int check_signature(struct signature_check *sigc,
 	if (!fmt)
 		die(_("bad/incompatible signature '%s'"), signature);
 
+	sigc->format_name = xstrdup(fmt->name);
+
 	if (parse_payload_metadata(sigc))
 		return 1;
 
@@ -782,6 +785,14 @@ void print_signature_buffer(const struct signature_check *sigc, unsigned flags)
 		fputs(output, stderr);
 }
 
+void print_signature_summary(const struct signature_check *sigc, unsigned flags)
+{
+	if (flags & GPG_VERIFY_SUMMARY)
+		printf("%c %s %s\n", sigc->result,
+		       sigc->format_name ? sigc->format_name : "?",
+		       sigc->sig_algo ? sigc->sig_algo : "?");
+}
+
 size_t parse_signed_buffer(const char *buf, size_t size)
 {
 	size_t len = 0;
diff --git a/gpg-interface.h b/gpg-interface.h
index 2b7701ca2c..a9565757f6 100644
--- a/gpg-interface.h
+++ b/gpg-interface.h
@@ -6,6 +6,7 @@ struct strbuf;
 #define GPG_VERIFY_VERBOSE	(1<<0)
 #define GPG_VERIFY_RAW		(1<<1)
 #define GPG_VERIFY_OMIT_STATUS	(1<<2)
+#define GPG_VERIFY_SUMMARY	(1<<3)
 
 enum signature_trust_level {
 	TRUST_UNDEFINED,
@@ -43,6 +44,9 @@ struct signature_check {
 	char *fingerprint;
 	char *primary_key_fingerprint;
 
+	/* "openpgp", "x509", "ssh" */
+	char *format_name;
+
 	/* hash algo for GPG/GPGSM, key type for SSH */
 	char *sig_algo;
 
@@ -95,5 +99,7 @@ int check_signature(struct signature_check *sigc,
 		    const char *signature, size_t slen);
 void print_signature_buffer(const struct signature_check *sigc,
 			    unsigned flags);
+void print_signature_summary(const struct signature_check *sigc,
+			     unsigned flags);
 
 #endif
diff --git a/t/t7510-signed-commit.sh b/t/t7510-signed-commit.sh
index 39677e859a..47f40862f3 100755
--- a/t/t7510-signed-commit.sh
+++ b/t/t7510-signed-commit.sh
@@ -232,6 +232,30 @@ test_expect_success GPG2 'bare signature' '
 	test_cmp expect actual
 '
 
+test_expect_success GPG 'verify signatures with --summary' '
+	# GPG-signed commit
+	git verify-commit --summary sixth-signed >actual &&
+	test_grep "^G openpgp sha1" actual &&
+
+	# Non-signed commit
+	test_must_fail git verify-commit --summary seventh-unsigned >actual 2>&1 &&
+	test_grep "^N ? ?" actual &&
+
+	# Trusted signature with alternate key (hash used might depend on the OS)
+	git verify-commit --summary eighth-signed-alt >actual &&
+	test_grep -E "^G openpgp sha(256|512)" actual &&
+
+	# Bad signature
+	test_must_fail git verify-commit --summary $(cat forged1.commit) >actual 2>err &&
+	test_grep "^B openpgp ?" actual
+'
+
+test_expect_success GPG '--summary and --raw work together' '
+	git verify-commit --summary --raw sixth-signed >actual 2>err &&
+	test_grep "^G openpgp sha1" actual &&
+	test_grep "GOODSIG" err
+'
+
 test_expect_success GPG 'show good signature with custom format' '
 	cat >expect <<-\EOF &&
 	G
diff --git a/t/t7528-signed-commit-ssh.sh b/t/t7528-signed-commit-ssh.sh
index 065f780636..3d0e7d7859 100755
--- a/t/t7528-signed-commit-ssh.sh
+++ b/t/t7528-signed-commit-ssh.sh
@@ -277,6 +277,34 @@ test_expect_success GPGSSH 'detect fudged signature with NUL' '
 	! grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual2
 '
 
+test_expect_success GPGSSH 'verify-commit --summary outputs format and key type for SSH signatures' '
+	test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
+
+	# SSH-signed commit with ED25519 key
+	git verify-commit --summary sixth-signed >actual &&
+	test_grep "^G ssh ED25519" actual &&
+
+	# SSH-signed commit with ECDSA key
+	git verify-commit --summary thirteenth-signed-ecdsa >actual &&
+	test_grep "^G ssh ECDSA" actual &&
+
+	# Non-signed commit
+	test_must_fail git verify-commit --summary seventh-unsigned >actual 2>&1 &&
+	test_grep "^N ? ?" actual &&
+
+	# Bad signature
+	test_must_fail git verify-commit --summary $(cat forged1.commit) >actual 2>err &&
+	test_grep "^B ssh ?" actual
+'
+
+test_expect_success GPGSSH '--summary and --raw work together' '
+	test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
+
+	git verify-commit --summary --raw sixth-signed >actual 2>err &&
+	test_grep "^G ssh ED25519" actual &&
+	test_grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" err
+'
+
 test_expect_success GPGSSH 'amending already signed commit' '
 	test_config gpg.format ssh &&
 	test_config user.signingkey "${GPGSSH_KEY_PRIMARY}" &&
-- 
2.49.0.609.g63c55177e5
Previous: Christian CouderNext: Elijah Newren
Message 27 of 65 in “fast-(import|export): improve on the signature algorithm name”
  1. fast-(import|export): improve on the signature algorithm nameChristian Couder, Apr 24, 2025
  2. Junio C HamanoApr 24, 2025
  3. Elijah NewrenApr 24, 2025
  4. Junio C HamanoApr 24, 2025
  5. Christian CouderMay 26, 2025
  6. Junio C HamanoMay 27, 2025
  7. Junio C HamanoMay 28, 2025
  8. Elijah NewrenMay 28, 2025
  9. Junio C HamanoMay 28, 2025
  10. Elijah NewrenMay 28, 2025
  11. Junio C HamanoMay 29, 2025
  12. Christian CouderJun 2, 2025
  13. Christian CouderJun 2, 2025
  14. Junio C HamanoJun 2, 2025
  15. Christian CouderMay 26, 2025
  16. Elijah NewrenApr 24, 2025
  17. Christian CouderMay 26, 2025
  18. brian m. carlsonApr 24, 2025
  19. Christian CouderMay 26, 2025
  20. Junio C HamanoApr 24, 2025
  21. 0/6 extract algo information from signaturesChristian Couder, May 26, 2025
  22. 1/6 gpg-interface: simplify ssh fingerprint parsingChristian Couder, May 26, 2025
  23. 2/6 gpg-interface: use left shift to define GPG_VERIFY_*Christian Couder, May 26, 2025
  24. 3/6 doc/verify-commit: update and improve the whole docChristian Couder, May 26, 2025
  25. 4/6 gpg-interface: extract hash algorithm from signature status outputChristian Couder, May 26, 2025
  26. 5/6 gpg-interface: extract SSH key type from signature status outputChristian Couder, May 26, 2025
  27. 6/6 verify-commit: add a --summary flagChristian Couder, May 26, 2025
  28. Elijah NewrenMay 26, 2025
  29. Christian CouderJun 19, 2025
  30. brian m. carlsonJun 2, 2025
  31. Christian CouderJun 19, 2025
  32. fast-(import|export): improve on commit signature output formatChristian Couder, Jun 18, 2025
  33. fast-(import|export): improve on commit signature output formatChristian Couder, Jun 19, 2025
  34. Junio C HamanoJun 19, 2025
  35. Christian CouderJul 8, 2025
  36. Elijah NewrenJun 19, 2025
  37. Christian CouderJun 20, 2025
  38. Junio C HamanoJun 20, 2025
  39. Christian CouderJul 8, 2025
  40. Elijah NewrenJun 26, 2025
  41. Christian CouderJul 8, 2025
  42. Junio C HamanoJul 7, 2025
  43. Christian CouderJul 8, 2025
  44. Junio C HamanoJul 8, 2025
  45. Patrick SteinhardtJul 8, 2025
  46. Christian CouderJul 8, 2025
  47. Junio C HamanoJul 8, 2025
  48. Christian CouderJul 9, 2025
  49. Junio C HamanoJul 9, 2025
  50. Patrick SteinhardtJul 10, 2025
  51. Christian CouderJul 10, 2025
  52. Junio C HamanoJul 10, 2025
  53. Christian CouderJul 8, 2025
  54. fast-(import|export): improve on commit signature output formatChristian Couder, Jul 8, 2025
  55. Junio C HamanoJul 8, 2025
  56. Elijah NewrenJul 8, 2025
  57. Junio C HamanoJul 9, 2025
  58. Elijah NewrenJul 9, 2025
  59. Christian CouderJul 9, 2025
  60. Christian CouderJul 9, 2025
  61. fast-(import|export): improve on commit signature output formatChristian Couder, Jul 9, 2025
  62. Junio C HamanoJul 9, 2025
  63. Elijah NewrenJul 14, 2025
  64. Junio C HamanoJul 14, 2025
  65. Christian CouderJul 25, 2025

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.