Skip to content

Commit 2b1546c

Browse files
jltoblergitster
authored andcommitted
fast-import: add 'sign-if-invalid' mode to '--signed-tags=<mode>'
With ee66c79 (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> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent 817b042 commit 2b1546c

File tree

2 files changed

+55
-6
lines changed

2 files changed

+55
-6
lines changed

builtin/fast-import.c

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ static const char *global_prefix;
191191
static enum sign_mode signed_tag_mode = SIGN_VERBATIM;
192192
static enum sign_mode signed_commit_mode = SIGN_VERBATIM;
193193
static const char *signed_commit_keyid;
194+
static const char *signed_tag_keyid;
194195

195196
/* Memory pools */
196197
static struct mem_pool fi_mem_pool = {
@@ -3110,6 +3111,19 @@ static void handle_tag_signature_if_invalid(struct strbuf *buf,
31103111

31113112
strbuf_setlen(msg, sig_offset);
31123113

3114+
if (signed_tag_mode == SIGN_SIGN_IF_INVALID) {
3115+
strbuf_attach(&payload, sigc.payload, sigc.payload_len,
3116+
sigc.payload_len + 1);
3117+
sigc.payload = NULL;
3118+
strbuf_reset(&signature);
3119+
3120+
if (sign_buffer(&payload, &signature, signed_tag_keyid,
3121+
SIGN_BUFFER_USE_DEFAULT_KEY))
3122+
die(_("failed to sign tag object"));
3123+
3124+
strbuf_addbuf(msg, &signature);
3125+
}
3126+
31133127
out:
31143128
signature_check_clear(&sigc);
31153129
strbuf_release(&signature);
@@ -3142,6 +3156,7 @@ static void handle_tag_signature(struct strbuf *buf, struct strbuf *msg, const c
31423156
/* Truncate the buffer to remove the signature */
31433157
strbuf_setlen(msg, sig_offset);
31443158
break;
3159+
case SIGN_SIGN_IF_INVALID:
31453160
case SIGN_STRIP_IF_INVALID:
31463161
handle_tag_signature_if_invalid(buf, msg, sig_offset);
31473162
break;
@@ -3153,9 +3168,6 @@ static void handle_tag_signature(struct strbuf *buf, struct strbuf *msg, const c
31533168
case SIGN_ABORT_IF_INVALID:
31543169
die(_("'abort-if-invalid' is not a valid mode for "
31553170
"git fast-import with --signed-tags=<mode>"));
3156-
case SIGN_SIGN_IF_INVALID:
3157-
die(_("'sign-if-invalid' is not a valid mode for "
3158-
"git fast-import with --signed-tags=<mode>"));
31593171
default:
31603172
BUG("invalid signed_tag_mode value %d from tag '%s'",
31613173
signed_tag_mode, name);
@@ -3749,7 +3761,7 @@ static int parse_one_option(const char *option)
37493761
if (parse_sign_mode(option, &signed_commit_mode, &signed_commit_keyid))
37503762
usagef(_("unknown --signed-commits mode '%s'"), option);
37513763
} else if (skip_prefix(option, "signed-tags=", &option)) {
3752-
if (parse_sign_mode(option, &signed_tag_mode, NULL))
3764+
if (parse_sign_mode(option, &signed_tag_mode, &signed_tag_keyid))
37533765
usagef(_("unknown --signed-tags mode '%s'"), option);
37543766
} else if (!strcmp(option, "quiet")) {
37553767
show_stats = 0;

t/t9306-fast-import-signed-tags.sh

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ test_expect_success GPGSSH 'import SSH signed tag with --signed-tags=strip' '
7777
test_grep ! "SSH SIGNATURE" out
7878
'
7979

80-
for mode in strip-if-invalid
80+
for mode in strip-if-invalid sign-if-invalid
8181
do
8282
test_expect_success GPG "import tag with no signature with --signed-tags=$mode" '
8383
test_when_finished rm -rf import &&
@@ -117,7 +117,15 @@ do
117117
IMPORTED=$(git -C import rev-parse --verify refs/tags/openpgp-signed) &&
118118
test $OPENPGP_SIGNED != $IMPORTED &&
119119
git -C import cat-file tag "$IMPORTED" >actual &&
120-
test_grep ! -E "^-----BEGIN PGP SIGNATURE-----" actual &&
120+
121+
if test "$mode" = strip-if-invalid
122+
then
123+
test_grep ! -E "^-----BEGIN PGP SIGNATURE-----" actual
124+
else
125+
test_grep -E "^-----BEGIN PGP SIGNATURE-----" actual &&
126+
git -C import verify-tag "$IMPORTED"
127+
fi &&
128+
121129
test_must_be_empty log
122130
'
123131

@@ -150,4 +158,33 @@ do
150158
'
151159
done
152160

161+
test_expect_success GPGSSH 'sign invalid tag with explicit keyid' '
162+
test_when_finished rm -rf import &&
163+
git init import &&
164+
165+
git fast-export --signed-tags=verbatim ssh-signed >output &&
166+
167+
# Change the tag message, which invalidates the signature. The tag
168+
# message length should not change though, otherwise the corresponding
169+
# `data <length>` command would have to be changed too.
170+
sed "s/SSH signed tag/SSH forged tag/" output >modified &&
171+
172+
# Configure the target repository with an invalid default signing key.
173+
test_config -C import user.signingkey "not-a-real-key-id" &&
174+
test_config -C import gpg.format ssh &&
175+
test_config -C import gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
176+
test_must_fail git -C import fast-import --quiet \
177+
--signed-tags=sign-if-invalid <modified >/dev/null 2>&1 &&
178+
179+
# Import using explicitly provided signing key.
180+
git -C import fast-import --quiet \
181+
--signed-tags=sign-if-invalid="${GPGSSH_KEY_PRIMARY}" <modified &&
182+
183+
IMPORTED=$(git -C import rev-parse --verify refs/tags/ssh-signed) &&
184+
test $SSH_SIGNED != $IMPORTED &&
185+
git -C import cat-file tag "$IMPORTED" >actual &&
186+
test_grep -E "^-----BEGIN SSH SIGNATURE-----" actual &&
187+
git -C import verify-tag "$IMPORTED"
188+
'
189+
153190
test_done

0 commit comments

Comments
 (0)