fast-import: add 'abort-if-invalid' mode to '--signed-commits=<mode>'

The '--signed-commits=<mode>' option for git-fast-import(1) configures
how signed commits are handled when encountered. In cases where an
invalid commit signature is encountered, a user may wish to abort the
operation entirely. Introduce an 'abort-if-invalid' mode to do so.

Signed-off-by: Justin Tobler <jltobler@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
maint
Justin Tobler 2026-03-26 14:14:11 -05:00 committed by Junio C Hamano
parent 6d35cc472e
commit 4c36345e04
6 changed files with 24 additions and 3 deletions

View File

@ -90,6 +90,8 @@ already trusted to run their own code.
commit signatures and replaces invalid signatures with newly created ones. commit signatures and replaces invalid signatures with newly created ones.
Valid signatures are left unchanged. If `<keyid>` is provided, that key is Valid signatures are left unchanged. If `<keyid>` is provided, that key is
used for signing; otherwise the configured default signing key is used. used for signing; otherwise the configured default signing key is used.
* `abort-if-invalid` will make this program die when encountering a signed
commit that is unable to be verified.


Options for Frontends Options for Frontends
~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~

View File

@ -65,7 +65,7 @@ static int parse_opt_sign_mode(const struct option *opt,
return 0; return 0;


if (parse_sign_mode(arg, val, NULL) || (*val == SIGN_STRIP_IF_INVALID) || if (parse_sign_mode(arg, val, NULL) || (*val == SIGN_STRIP_IF_INVALID) ||
(*val == SIGN_SIGN_IF_INVALID)) (*val == SIGN_SIGN_IF_INVALID) || (*val == SIGN_ABORT_IF_INVALID))
return error(_("unknown %s mode: %s"), opt->long_name, arg); return error(_("unknown %s mode: %s"), opt->long_name, arg);


return 0; return 0;

View File

@ -2892,6 +2892,9 @@ static void handle_signature_if_invalid(struct strbuf *new_data,
ret = verify_commit_buffer(tmp_buf.buf, tmp_buf.len, &signature_check); ret = verify_commit_buffer(tmp_buf.buf, tmp_buf.len, &signature_check);


if (ret) { if (ret) {
if (mode == SIGN_ABORT_IF_INVALID)
die(_("aborting due to invalid signature"));

warn_invalid_signature(&signature_check, msg->buf, mode); warn_invalid_signature(&signature_check, msg->buf, mode);


if (mode == SIGN_SIGN_IF_INVALID) { if (mode == SIGN_SIGN_IF_INVALID) {
@ -2983,6 +2986,7 @@ static void parse_new_commit(const char *arg)
case SIGN_VERBATIM: case SIGN_VERBATIM:
case SIGN_STRIP_IF_INVALID: case SIGN_STRIP_IF_INVALID:
case SIGN_SIGN_IF_INVALID: case SIGN_SIGN_IF_INVALID:
case SIGN_ABORT_IF_INVALID:
import_one_signature(&sig_sha1, &sig_sha256, v); import_one_signature(&sig_sha1, &sig_sha256, v);
break; break;


@ -3068,7 +3072,8 @@ static void parse_new_commit(const char *arg)
encoding); encoding);


if ((signed_commit_mode == SIGN_STRIP_IF_INVALID || if ((signed_commit_mode == SIGN_STRIP_IF_INVALID ||
signed_commit_mode == SIGN_SIGN_IF_INVALID) && signed_commit_mode == SIGN_SIGN_IF_INVALID ||
signed_commit_mode == SIGN_ABORT_IF_INVALID) &&
(sig_sha1.hash_algo || sig_sha256.hash_algo)) (sig_sha1.hash_algo || sig_sha256.hash_algo))
handle_signature_if_invalid(&new_data, &sig_sha1, &sig_sha256, handle_signature_if_invalid(&new_data, &sig_sha1, &sig_sha256,
&msg, signed_commit_mode); &msg, signed_commit_mode);
@ -3115,6 +3120,9 @@ static void handle_tag_signature(struct strbuf *msg, const char *name)
case SIGN_ABORT: case SIGN_ABORT:
die(_("encountered signed tag; use " die(_("encountered signed tag; use "
"--signed-tags=<mode> to handle it")); "--signed-tags=<mode> to handle it"));
case SIGN_ABORT_IF_INVALID:
die(_("'abort-if-invalid' is not a valid mode for "
"git fast-import with --signed-tags=<mode>"));
case SIGN_STRIP_IF_INVALID: case SIGN_STRIP_IF_INVALID:
die(_("'strip-if-invalid' is not a valid mode for " die(_("'strip-if-invalid' is not a valid mode for "
"git fast-import with --signed-tags=<mode>")); "git fast-import with --signed-tags=<mode>"));

View File

@ -1164,6 +1164,8 @@ int parse_sign_mode(const char *arg, enum sign_mode *mode, const char **keyid)
*mode = SIGN_WARN_STRIP; *mode = SIGN_WARN_STRIP;
} else if (!strcmp(arg, "strip")) { } else if (!strcmp(arg, "strip")) {
*mode = SIGN_STRIP; *mode = SIGN_STRIP;
} else if (!strcmp(arg, "abort-if-invalid")) {
*mode = SIGN_ABORT_IF_INVALID;
} else if (!strcmp(arg, "strip-if-invalid")) { } else if (!strcmp(arg, "strip-if-invalid")) {
*mode = SIGN_STRIP_IF_INVALID; *mode = SIGN_STRIP_IF_INVALID;
} else if (!strcmp(arg, "sign-if-invalid")) { } else if (!strcmp(arg, "sign-if-invalid")) {

View File

@ -115,6 +115,7 @@ void print_signature_buffer(const struct signature_check *sigc,
/* Modes for --signed-tags=<mode> and --signed-commits=<mode> options. */ /* Modes for --signed-tags=<mode> and --signed-commits=<mode> options. */
enum sign_mode { enum sign_mode {
SIGN_ABORT, SIGN_ABORT,
SIGN_ABORT_IF_INVALID,
SIGN_WARN_VERBATIM, SIGN_WARN_VERBATIM,
SIGN_VERBATIM, SIGN_VERBATIM,
SIGN_WARN_STRIP, SIGN_WARN_STRIP,

View File

@ -103,7 +103,7 @@ test_expect_success RUST,GPG 'strip both OpenPGP signatures with --signed-commit
test_line_count = 2 out test_line_count = 2 out
' '


for mode in strip-if-invalid sign-if-invalid for mode in strip-if-invalid sign-if-invalid abort-if-invalid
do do
test_expect_success GPG "import commit with no signature with --signed-commits=$mode" ' test_expect_success GPG "import commit with no signature with --signed-commits=$mode" '
git fast-export main >output && git fast-export main >output &&
@ -135,6 +135,14 @@ do
# corresponding `data <length>` command would have to be changed too. # corresponding `data <length>` command would have to be changed too.
sed "s/OpenPGP signed commit/OpenPGP forged commit/" output >modified && sed "s/OpenPGP signed commit/OpenPGP forged commit/" output >modified &&


if test "$mode" = abort-if-invalid
then
test_must_fail git -C new fast-import --quiet \
--signed-commits=$mode <modified >log 2>&1 &&
test_grep "aborting due to invalid signature" log &&
return 0
fi &&

git -C new fast-import --quiet --signed-commits=$mode <modified >log 2>&1 && git -C new fast-import --quiet --signed-commits=$mode <modified >log 2>&1 &&


IMPORTED=$(git -C new rev-parse --verify refs/heads/openpgp-signing) && IMPORTED=$(git -C new rev-parse --verify refs/heads/openpgp-signing) &&