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

[PATCH v6 0/3] fast-import: add mode to re-sign invalid commit signatures

From
Justin Tobler <jltobler@gmail.com>
Date
Mar 13, 2026, 01:39 UTC
Message-ID
<20260313013938.2742124-1-jltobler@gmail.com>
In-Reply-To
<20260312192228.481134-1-jltobler@gmail.com>
Greetings,

With c20f112e51 (fast-import: add 'strip-if-invalid' mode to --signed-commits=<mode>, 2025-11-17), it became possible to remove invalid signatures from commits via git-fast-import(1) while maintaining valid commit signatures. Building upon this functionality, a user may want to re-sign these invalid commit signatures. This series introduces the `sign-if-invalid` mode to do so accordingly.

The newly added mode in this series currently ignores `extensions.compatObjectFormat` when generating the new signatures. From my understanding, to generate the compatibility structure would also require us to reconstruct the compatibility object for the object being signed. I think this would be possible to do, but would require getting the mapped OIDs for the commit parents and tree. I'm not completely sure of a good way to go about this yet though. I'm also not completely certain if this is something that should be addressed as part of this series, or could be done later down the road. So for now I've opted to delay its implementation. I'm open going down the other route if that is preferred though.

The first commit is a simple cleanup for something I noticed while reading though commit signing code. The second commit actually introduces the new `--signed-commits` mode.

Changes since V5:
- Fixed a test that was incorrectly referencing the openpgp-signing
  branch when it should be using the ssh-signing branch.
- Changed warning message wording.
- Added some parentheses in a conditional statement to clarify operation
  order.
Changes since V4:
- Instead of introducing a separate `sign_buffer_with_key()` helper,
  extend `sign_buffer()` to support a SIGN_BUFFER_USE_DEFAULT_KEY flag.
- Fixed message in die().
Changes since V3:
- Rename the `re-sign-if-invalid` mode to `sign-if-invalid`. The
  "if-invalid" already implies the signatures was previously signed
  making "re-sign" redundant.
Changes since V2:
- Adapted commit message in second patch to improve clarity.
- Fixed typos.
- Renamed SIGN_RESIGN_IF_INVALID to SIGN_RE_SIGN_IF_INVALID.
- Created separate helper function to handle printing invalid signature
  warnings.
Changes since V1:
- Improved commit messages and comments to better explain why
  interoperability mode is not currently supported.
- Clarified documentation for re-sign-if-invalid mode.
- Renamed `handle_invalid_signature()` to `handle_signature_if_invalid()`.
- Added warning messages specific to commit resigning.
- Fixed some small typos.
- Added support for explicitly specifying the signing key ID via
  `--signed-commits=re-sign-if-invalid[=<keyid>]` similar to how it can
  specified in git-commit(1).
- We now die() as unsupported when attempting to re-sign an invalid
  commit signature in interoperability mode.
- We now die() when failing to re-sign a commit.

Thanks, -Justin

Justin Tobler (3):
  commit: remove unused forward declaration
  gpg-interface: allow sign_buffer() to use default signing key
  fast-import: add mode to sign commits with invalid signatures
 Documentation/git-fast-import.adoc |   4 +
 builtin/fast-export.c              |   8 +-
 builtin/fast-import.c              | 101 +++++++++++++++-----
 builtin/tag.c                      |   4 +-
 commit.c                           |  19 +---
 commit.h                           |   2 -
 gpg-interface.c                    |  36 ++++++--
 gpg-interface.h                    |  19 +++-
 send-pack.c                        |   2 +-
 t/t9305-fast-import-signatures.sh  | 144 ++++++++++++++++++-----------
 10 files changed, 231 insertions(+), 108 deletions(-)
Range-diff against v5:
1:  0d00b72ee0 = 1:  0d00b72ee0 commit: remove unused forward declaration
2:  7a0deed77b ! 2:  5224c1766f gpg-interface: allow sign_buffer() to use default signing key
    @@ gpg-interface.c: const char *gpg_trust_level_to_str(enum signature_trust_level l
      	gpg_interface_lazy_init();
      
     -	return use_format->sign_buffer(buffer, signature, signing_key);
    -+	if (flags & SIGN_BUFFER_USE_DEFAULT_KEY && (!signing_key || !*signing_key))
    ++	if ((flags & SIGN_BUFFER_USE_DEFAULT_KEY) && (!signing_key || !*signing_key))
     +		signing_key = keyid_to_free = get_signing_key();
     +
     +	ret = use_format->sign_buffer(buffer, signature, signing_key);
3:  e659971e84 ! 3:  d9ad73e05b fast-import: add mode to sign commits with invalid signatures
    @@ builtin/fast-import.c: static void handle_strip_if_invalid(struct strbuf *new_da
     +		break;
     +	case SIGN_SIGN_IF_INVALID:
     +		if (subject_len > 100)
    -+			warning(_("signing commit with invalid signature for '%.100s...'\n"
    ++			warning(_("replacing invalid signature for commit '%.100s...'\n"
     +				  "  allegedly by %s"), subject, signer);
     +		else if (subject_len > 0)
    -+			warning(_("signing commit with invalid signature for '%.*s'\n"
    ++			warning(_("replacing invalid signature for commit '%.*s'\n"
     +				  "  allegedly by %s"), subject_len, subject, signer);
     +		else
    -+			warning(_("signing commit with invalid signature\n"
    ++			warning(_("replacing invalid signature for commit\n"
     +				  "  allegedly by %s"), signer);
     +		break;
     +	default:
    @@ t/t9305-fast-import-signatures.sh: test_expect_success GPG 'strip both OpenPGP s
     +			test_grep "stripping invalid signature" log &&
     +			test_grep ! -E "^gpgsig" actual
     +		else
    -+			test_grep "signing commit with invalid signature" log &&
    ++			test_grep "replacing invalid signature" log &&
     +			test_grep -E "^gpgsig(-sha256)? " actual &&
     +			git -C new verify-commit "$IMPORTED"
     +		fi
    @@ t/t9305-fast-import-signatures.sh: test_expect_success GPG 'strip both OpenPGP s
      	rm -rf new &&
      	git init new &&
      
    -@@ t/t9305-fast-import-signatures.sh: test_expect_success GPG 'strip signature invalidated by message change with --si
    - 	# corresponding `data <length>` command would have to be changed too.
    - 	sed "s/OpenPGP signed commit/OpenPGP forged commit/" output >modified &&
    +-	git fast-export --signed-commits=verbatim openpgp-signing >output &&
    ++	git fast-export --signed-commits=verbatim ssh-signing >output &&
      
    + 	# Change the commit message, which invalidates the signature.
    + 	# The commit message length should not change though, otherwise the
    + 	# corresponding `data <length>` command would have to be changed too.
    +-	sed "s/OpenPGP signed commit/OpenPGP forged commit/" output >modified &&
    +-
     -	git -C new fast-import --quiet --signed-commits=strip-if-invalid <modified >log 2>&1 &&
    -+	# Configure the target repository with an invalid default signing key.
    -+	test_config -C new user.signingkey "not-a-real-key-id" &&
    -+	test_config -C new gpg.format ssh &&
    -+	test_config -C new gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
    -+	test_must_fail git -C new fast-import --quiet \
    -+		--signed-commits=sign-if-invalid <modified >/dev/null 2>&1 &&
    -+
    -+	# Import using explicitly provided signing key.
    -+	git -C new fast-import --quiet \
    -+		--signed-commits=sign-if-invalid="${GPGSSH_KEY_PRIMARY}" <modified &&
    - 
    - 	IMPORTED=$(git -C new rev-parse --verify refs/heads/openpgp-signing) &&
    - 	test $OPENPGP_SIGNING != $IMPORTED &&
    - 	git -C new cat-file commit "$IMPORTED" >actual &&
    +-
    +-	IMPORTED=$(git -C new rev-parse --verify refs/heads/openpgp-signing) &&
    +-	test $OPENPGP_SIGNING != $IMPORTED &&
    +-	git -C new cat-file commit "$IMPORTED" >actual &&
     -	test_grep ! -E "^gpgsig" actual &&
     -	test_grep "stripping invalid signature" log
     -'
    @@ t/t9305-fast-import-signatures.sh: test_expect_success GPG 'strip signature inva
     -	IMPORTED=$(git -C new rev-parse --verify refs/heads/x509-signing) &&
     -	test $X509_SIGNING = $IMPORTED &&
     -	git -C new cat-file commit "$IMPORTED" >actual &&
    - 	test_grep -E "^gpgsig(-sha256)? " actual &&
    +-	test_grep -E "^gpgsig(-sha256)? " actual &&
     -	test_must_be_empty log
     -'
     -
     -test_expect_success GPGSSH 'keep valid SSH signature with --signed-commits=strip-if-invalid' '
     -	rm -rf new &&
     -	git init new &&
    --
    --	test_config -C new gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
    --
    ++	sed "s/SSH signed commit/SSH forged commit/" output >modified &&
    + 
    ++	# Configure the target repository with an invalid default signing key.
    ++	test_config -C new user.signingkey "not-a-real-key-id" &&
    ++	test_config -C new gpg.format ssh &&
    + 	test_config -C new gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
    ++	test_must_fail git -C new fast-import --quiet \
    ++		--signed-commits=sign-if-invalid <modified >/dev/null 2>&1 &&
    ++
    ++	# Import using explicitly provided signing key.
    ++	git -C new fast-import --quiet \
    ++		--signed-commits=sign-if-invalid="${GPGSSH_KEY_PRIMARY}" <modified &&
    + 
     -	git fast-export --signed-commits=verbatim ssh-signing >output &&
     -	git -C new fast-import --quiet --signed-commits=strip-if-invalid <output >log 2>&1 &&
    --	IMPORTED=$(git -C new rev-parse --verify refs/heads/ssh-signing) &&
    + 	IMPORTED=$(git -C new rev-parse --verify refs/heads/ssh-signing) &&
     -	test $SSH_SIGNING = $IMPORTED &&
    --	git -C new cat-file commit "$IMPORTED" >actual &&
    --	test_grep -E "^gpgsig(-sha256)? " actual &&
    ++	test $SSH_SIGNING != $IMPORTED &&
    + 	git -C new cat-file commit "$IMPORTED" >actual &&
    + 	test_grep -E "^gpgsig(-sha256)? " actual &&
     -	test_must_be_empty log
     +	git -C new verify-commit "$IMPORTED"
      '
base-commit: 7c02d39fc2ed2702223c7674f73150d9a7e61ba4
-- 
2.53.0.381.g628a66ccf6
Previous: Justin ToblerNext: Justin Tobler
Message 53 of 60 in “fast-import: add mode to re-sign invalid commit signatures”
  1. 0/2 fast-import: add mode to re-sign invalid commit signaturesJustin Tobler, Feb 23, 2026
  2. 1/2 commit: remove unused forward declarationJustin Tobler, Feb 23, 2026
  3. Patrick SteinhardtFeb 24, 2026
  4. 2/2 fast-import: add mode to re-sign invalid commit signaturesJustin Tobler, Feb 23, 2026
  5. Patrick SteinhardtFeb 24, 2026
  6. Justin ToblerFeb 24, 2026
  7. Christian CouderFeb 24, 2026
  8. brian m. carlsonFeb 24, 2026
  9. Junio C HamanoFeb 24, 2026
  10. Justin ToblerMar 2, 2026
  11. 0/3 fast-import: add mode to re-sign invalid commit signaturesJustin Tobler, Mar 6, 2026
  12. 1/3 commit: remove unused forward declarationJustin Tobler, Mar 6, 2026
  13. 2/3 gpg-interface: introduce sign_buffer_with_key()Justin Tobler, Mar 6, 2026
  14. Christian CouderMar 10, 2026
  15. Justin ToblerMar 10, 2026
  16. 3/3 fast-import: add mode to re-sign invalid commit signaturesJustin Tobler, Mar 6, 2026
  17. Christian CouderMar 10, 2026
  18. Justin ToblerMar 10, 2026
  19. 0/3 fast-import: add mode to re-sign invalid commit signaturesJustin Tobler, Mar 10, 2026
  20. 1/3 commit: remove unused forward declarationJustin Tobler, Mar 10, 2026
  21. Junio C HamanoMar 10, 2026
  22. 2/3 gpg-interface: introduce sign_buffer_with_key()Justin Tobler, Mar 10, 2026
  23. Junio C HamanoMar 10, 2026
  24. 3/3 fast-import: add mode to re-sign invalid commit signaturesJustin Tobler, Mar 10, 2026
  25. Junio C HamanoMar 10, 2026
  26. Justin ToblerMar 10, 2026
  27. Junio C HamanoMar 10, 2026
  28. Justin ToblerMar 10, 2026
  29. Junio C HamanoMar 10, 2026
  30. Justin ToblerMar 10, 2026
  31. 0/3 fast-import: add mode to re-sign invalid commit signaturesJustin Tobler, Mar 11, 2026
  32. 1/3 commit: remove unused forward declarationJustin Tobler, Mar 11, 2026
  33. 2/3 gpg-interface: introduce sign_buffer_with_key()Justin Tobler, Mar 11, 2026
  34. Patrick SteinhardtMar 12, 2026
  35. Justin ToblerMar 12, 2026
  36. 3/3 fast-import: add mode to sign commits with invalid signaturesJustin Tobler, Mar 11, 2026
  37. Patrick SteinhardtMar 12, 2026
  38. Justin ToblerMar 12, 2026
  39. Patrick SteinhardtMar 12, 2026
  40. Justin ToblerMar 12, 2026
  41. 0/3 fast-import: add mode to re-sign invalid commit signaturesJustin Tobler, Mar 12, 2026
  42. 1/3 commit: remove unused forward declarationJustin Tobler, Mar 12, 2026
  43. 2/3 gpg-interface: allow sign_buffer() to use default signing keyJustin Tobler, Mar 12, 2026
  44. Junio C HamanoMar 12, 2026
  45. Justin ToblerMar 12, 2026
  46. 3/3 fast-import: add mode to sign commits with invalid signaturesJustin Tobler, Mar 12, 2026
  47. Junio C HamanoMar 12, 2026
  48. Justin ToblerMar 12, 2026
  49. Jeff KingMar 12, 2026
  50. Justin ToblerMar 13, 2026
  51. Junio C HamanoMar 12, 2026
  52. Justin ToblerMar 12, 2026
  53. 0/3 fast-import: add mode to re-sign invalid commit signaturesJustin Tobler, Mar 13, 2026
  54. 1/3 commit: remove unused forward declarationJustin Tobler, Mar 13, 2026
  55. 2/3 gpg-interface: allow sign_buffer() to use default signing keyJustin Tobler, Mar 13, 2026
  56. Patrick SteinhardtMar 13, 2026
  57. 3/3 fast-import: add mode to sign commits with invalid signaturesJustin Tobler, Mar 13, 2026
  58. Patrick SteinhardtMar 13, 2026
  59. Junio C HamanoMar 13, 2026
  60. Patrick SteinhardtMar 13, 2026

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.