From: Justin Tobler <jltobler@gmail.com>
To: git@vger.kernel.org
Cc: christian.couder@gmail.com, gitster@pobox.com,
Justin Tobler <jltobler@gmail.com>
Subject: [PATCH v2 4/5] fast-import: add 'sign-if-invalid' mode to '--signed-tags=<mode>'
Date: Thu, 26 Mar 2026 14:14:13 -0500 [thread overview]
Message-ID: <20260326191414.3783974-5-jltobler@gmail.com> (raw)
In-Reply-To: <20260326191414.3783974-1-jltobler@gmail.com>
With ee66c793f8 (fast-import: add mode to sign commits with invalid
signatures, 2026-03-12), git-fast-import(1) learned to verify commit
signatures during import and replace signatures that fail verification
with a newly generated one. Extend the same behavior to signed tag
objects by introducing a 'sign-if-invalid' mode for the '--signed-tags'
option.
Signed-off-by: Justin Tobler <jltobler@gmail.com>
---
builtin/fast-import.c | 20 ++++++++++++---
t/t9306-fast-import-signed-tags.sh | 41 ++++++++++++++++++++++++++++--
2 files changed, 55 insertions(+), 6 deletions(-)
diff --git a/builtin/fast-import.c b/builtin/fast-import.c
index 5e89829aea..783e0e7ab4 100644
--- a/builtin/fast-import.c
+++ b/builtin/fast-import.c
@@ -191,6 +191,7 @@ static const char *global_prefix;
static enum sign_mode signed_tag_mode = SIGN_VERBATIM;
static enum sign_mode signed_commit_mode = SIGN_VERBATIM;
static const char *signed_commit_keyid;
+static const char *signed_tag_keyid;
/* Memory pools */
static struct mem_pool fi_mem_pool = {
@@ -3110,6 +3111,19 @@ static void handle_tag_signature_if_invalid(struct strbuf *buf,
strbuf_setlen(msg, sig_offset);
+ if (signed_tag_mode == SIGN_SIGN_IF_INVALID) {
+ strbuf_attach(&payload, sigc.payload, sigc.payload_len,
+ sigc.payload_len + 1);
+ sigc.payload = NULL;
+ strbuf_reset(&signature);
+
+ if (sign_buffer(&payload, &signature, signed_tag_keyid,
+ SIGN_BUFFER_USE_DEFAULT_KEY))
+ die(_("failed to sign tag object"));
+
+ strbuf_addbuf(msg, &signature);
+ }
+
out:
signature_check_clear(&sigc);
strbuf_release(&signature);
@@ -3142,6 +3156,7 @@ static void handle_tag_signature(struct strbuf *buf, struct strbuf *msg, const c
/* Truncate the buffer to remove the signature */
strbuf_setlen(msg, sig_offset);
break;
+ case SIGN_SIGN_IF_INVALID:
case SIGN_STRIP_IF_INVALID:
handle_tag_signature_if_invalid(buf, msg, sig_offset);
break;
@@ -3153,9 +3168,6 @@ static void handle_tag_signature(struct strbuf *buf, struct strbuf *msg, const c
case SIGN_ABORT_IF_INVALID:
die(_("'abort-if-invalid' is not a valid mode for "
"git fast-import with --signed-tags=<mode>"));
- case SIGN_SIGN_IF_INVALID:
- die(_("'sign-if-invalid' is not a valid mode for "
- "git fast-import with --signed-tags=<mode>"));
default:
BUG("invalid signed_tag_mode value %d from tag '%s'",
signed_tag_mode, name);
@@ -3749,7 +3761,7 @@ static int parse_one_option(const char *option)
if (parse_sign_mode(option, &signed_commit_mode, &signed_commit_keyid))
usagef(_("unknown --signed-commits mode '%s'"), option);
} else if (skip_prefix(option, "signed-tags=", &option)) {
- if (parse_sign_mode(option, &signed_tag_mode, NULL))
+ if (parse_sign_mode(option, &signed_tag_mode, &signed_tag_keyid))
usagef(_("unknown --signed-tags mode '%s'"), option);
} else if (!strcmp(option, "quiet")) {
show_stats = 0;
diff --git a/t/t9306-fast-import-signed-tags.sh b/t/t9306-fast-import-signed-tags.sh
index fd43b0b52a..bb4c8008ef 100755
--- a/t/t9306-fast-import-signed-tags.sh
+++ b/t/t9306-fast-import-signed-tags.sh
@@ -77,7 +77,7 @@ test_expect_success GPGSSH 'import SSH signed tag with --signed-tags=strip' '
test_grep ! "SSH SIGNATURE" out
'
-for mode in strip-if-invalid
+for mode in strip-if-invalid sign-if-invalid
do
test_expect_success GPG "import tag with no signature with --signed-tags=$mode" '
test_when_finished rm -rf import &&
@@ -117,7 +117,15 @@ do
IMPORTED=$(git -C import rev-parse --verify refs/tags/openpgp-signed) &&
test $OPENPGP_SIGNED != $IMPORTED &&
git -C import cat-file tag "$IMPORTED" >actual &&
- test_grep ! -E "^-----BEGIN PGP SIGNATURE-----" actual &&
+
+ if test "$mode" = strip-if-invalid
+ then
+ test_grep ! -E "^-----BEGIN PGP SIGNATURE-----" actual
+ else
+ test_grep -E "^-----BEGIN PGP SIGNATURE-----" actual &&
+ git -C import verify-tag "$IMPORTED"
+ fi &&
+
test_must_be_empty log
'
@@ -150,4 +158,33 @@ do
'
done
+test_expect_success GPGSSH 'sign invalid tag with explicit keyid' '
+ test_when_finished rm -rf import &&
+ git init import &&
+
+ git fast-export --signed-tags=verbatim ssh-signed >output &&
+
+ # Change the tag message, which invalidates the signature. The tag
+ # message length should not change though, otherwise the corresponding
+ # `data <length>` command would have to be changed too.
+ sed "s/SSH signed tag/SSH forged tag/" output >modified &&
+
+ # Configure the target repository with an invalid default signing key.
+ test_config -C import user.signingkey "not-a-real-key-id" &&
+ test_config -C import gpg.format ssh &&
+ test_config -C import gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
+ test_must_fail git -C import fast-import --quiet \
+ --signed-tags=sign-if-invalid <modified >/dev/null 2>&1 &&
+
+ # Import using explicitly provided signing key.
+ git -C import fast-import --quiet \
+ --signed-tags=sign-if-invalid="${GPGSSH_KEY_PRIMARY}" <modified &&
+
+ IMPORTED=$(git -C import rev-parse --verify refs/tags/ssh-signed) &&
+ test $SSH_SIGNED != $IMPORTED &&
+ git -C import cat-file tag "$IMPORTED" >actual &&
+ test_grep -E "^-----BEGIN SSH SIGNATURE-----" actual &&
+ git -C import verify-tag "$IMPORTED"
+'
+
test_done
--
2.53.0.381.g628a66ccf6
next prev parent reply other threads:[~2026-03-26 19:14 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-26 19:14 [PATCH v2 0/5] fast-import: extend signed object handling modes Justin Tobler
2026-03-26 19:14 ` [PATCH v2 1/5] fast-export: check for unsupported signing modes earlier Justin Tobler
2026-03-26 19:14 ` [PATCH v2 2/5] fast-import: add 'abort-if-invalid' mode to '--signed-commits=<mode>' Justin Tobler
2026-03-26 19:14 ` [PATCH v2 3/5] fast-import: add 'strip-if-invalid' mode to '--signed-tags=<mode>' Justin Tobler
2026-03-26 19:14 ` Justin Tobler [this message]
2026-03-26 19:14 ` [PATCH v2 5/5] fast-import: add 'abort-if-invalid' " Justin Tobler
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260326191414.3783974-5-jltobler@gmail.com \
--to=jltobler@gmail.com \
--cc=christian.couder@gmail.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox