Message ID | 20250224142744.279643-1-christian.couder@gmail.com (mailing list archive) |
---|---|
Headers | show |
Series | fast-export, fast-import: add support for signed-commits | expand |
Christian Couder <christian.couder@gmail.com> writes: > Luke Shumaker sent the first 4 versions of this series in April 2021, > but it looks like he stopped before it got merged. Let's finish > polishing it. Nice to see an old topic resurrected. > fast-export has an existing --signed-tags= option that controls how to > handle tag signatures. However, there is no equivalent for commit > signatures; it just silently strips the signature out of the commit > (analogously to --signed-tags=strip). > > So implement a --signed-commits= flag in fast-export, and implement > the receiving side of it in fast-import. Nice. I haven't thought about this topic obviously for a looooong time, but I wonder we may want to have an option, which is independent from these --signed-tags/--signed-commits options addressed here, that allows the person who performed the import to attest to the result by adding their own signature on tags and commits, whether these tags and commits were originally signed or not. Obviously totally independent, orthogonal, and outside of the scope of this topic. Thanks.
On Mon, Feb 24, 2025 at 9:01 AM Junio C Hamano <gitster@pobox.com> wrote: > > Christian Couder <christian.couder@gmail.com> writes: > > > Luke Shumaker sent the first 4 versions of this series in April 2021, > > but it looks like he stopped before it got merged. Let's finish > > polishing it. > > Nice to see an old topic resurrected. > > > fast-export has an existing --signed-tags= option that controls how to > > handle tag signatures. However, there is no equivalent for commit > > signatures; it just silently strips the signature out of the commit > > (analogously to --signed-tags=strip). > > > > So implement a --signed-commits= flag in fast-export, and implement > > the receiving side of it in fast-import. > > Nice. > > I haven't thought about this topic obviously for a looooong time, > but I wonder we may want to have an option, which is independent > from these --signed-tags/--signed-commits options addressed here, > that allows the person who performed the import to attest to the > result by adding their own signature on tags and commits, whether > these tags and commits were originally signed or not. For what it's worth, this has been requested multiple times of git-filter-repo, so there is some desire for this feature. > Obviously totally independent, orthogonal, and outside of the scope > of this topic. Agreed.
On Mon, Feb 24, 2025 at 11:35:00PM -0800, Elijah Newren wrote: > On Mon, Feb 24, 2025 at 9:01 AM Junio C Hamano <gitster@pobox.com> wrote: > > > > Christian Couder <christian.couder@gmail.com> writes: > > > > > Luke Shumaker sent the first 4 versions of this series in April 2021, > > > but it looks like he stopped before it got merged. Let's finish > > > polishing it. > > > > Nice to see an old topic resurrected. > > > > > fast-export has an existing --signed-tags= option that controls how to > > > handle tag signatures. However, there is no equivalent for commit > > > signatures; it just silently strips the signature out of the commit > > > (analogously to --signed-tags=strip). > > > > > > So implement a --signed-commits= flag in fast-export, and implement > > > the receiving side of it in fast-import. > > > > Nice. > > > > I haven't thought about this topic obviously for a looooong time, > > but I wonder we may want to have an option, which is independent > > from these --signed-tags/--signed-commits options addressed here, > > that allows the person who performed the import to attest to the > > result by adding their own signature on tags and commits, whether > > these tags and commits were originally signed or not. > > For what it's worth, this has been requested multiple times of > git-filter-repo, so there is some desire for this feature. This is also exactly the usecase we have been reviving this effort for :) We recently hit such a case where a customer was basically unable to use git-filter-repo(1) due to commit signatures, so we wanted to help out and get this patch series landed so that the issue can ultimately be addressed in git-filter-repo(1). Patrick
Hi Christian I've only glanced over this series, but I did notice a memory leak On 24/02/2025 14:27, Christian Couder wrote: > > + * The returned string has had the ' ' line continuation markers > -+ * removed, and points to staticly allocated memory (not to memory > ++ * removed, and points to statically allocated memory (not to memory This corrects the spelling but the changes below remove the static buffer so the user is now responsible for freeing the returned string. That means this comment is wrong and I don't see any corresponding changes to the callers to free the memory. > + * within 'msg'), so it is only valid until the next call to > + * find_commit_multiline_header. > + * > @@ builtin/fast-export.c: static void anonymize_ident_line(const char **beg, const > + const char *key, > + const char **end) > +{ > -+ static struct strbuf val = STRBUF_INIT; > ++ struct strbuf val = STRBUF_INIT; > + const char *bol, *eol; > + size_t len; > + > -+ strbuf_reset(&val); > -+ > + bol = find_commit_header(msg, key, &len); > + if (!bol) > + return NULL; > @@ builtin/fast-export.c: static void anonymize_ident_line(const char **beg, const > + } > + > + *end = eol; > -+ return val.buf; > ++ return strbuf_detach(&val, NULL); > +} Best Wishes Phillip > - static char *reencode_message(const char *in_msg, > - const char *in_encoding, size_t in_encoding_len) > + static void handle_commit(struct commit *commit, struct rev_info *rev, > + struct string_list *paths_of_changed_objects) > { > @@ builtin/fast-export.c: static void handle_commit(struct commit *commit, struct rev_info *rev, > const char *author, *author_end, *committer, *committer_end; > - const char *encoding; > + const char *encoding = NULL; > size_t encoding_len; > -+ const char *signature_alg = NULL, *signature; > ++ const char *signature_alg = NULL, *signature = NULL; > const char *message; > char *reencoded = NULL; > struct commit_list *p; > @@ builtin/fast-export.c: static void handle_commit(struct commit *commit, struct rev_info *rev, > - committer++; > commit_buffer_cursor = committer_end = strchrnul(committer, '\n'); > > -- /* find_commit_header() gets a `+ 1` because > + /* > +- * find_commit_header() gets a `+ 1` because > - * commit_buffer_cursor points at the trailing "\n" at the end > - * of the previous line, but find_commit_header() wants a > -+ /* find_commit_header() and find_commit_multiline_header() get > ++ * find_commit_header() and find_commit_multiline_header() get > + * a `+ 1` because commit_buffer_cursor points at the trailing > + * "\n" at the end of the previous line, but they want a > - * pointer to the beginning of the next line. */ > + * pointer to the beginning of the next line. > + */ > + > - encoding = find_commit_header(commit_buffer_cursor + 1, "encoding", &encoding_len); > - if (encoding) > - commit_buffer_cursor = encoding + encoding_len; > + if (*commit_buffer_cursor == '\n') { > + encoding = find_commit_header(commit_buffer_cursor + 1, "encoding", &encoding_len); > + if (encoding) > + commit_buffer_cursor = encoding + encoding_len; > + } > > -+ if ((signature = find_commit_multiline_header(commit_buffer_cursor + 1, "gpgsig", &commit_buffer_cursor))) > -+ signature_alg = "sha1"; > -+ else if ((signature = find_commit_multiline_header(commit_buffer_cursor + 1, "gpgsig-sha256", &commit_buffer_cursor))) > -+ signature_alg = "sha256"; > ++ if (*commit_buffer_cursor == '\n') { > ++ if ((signature = find_commit_multiline_header(commit_buffer_cursor + 1, "gpgsig", &commit_buffer_cursor))) > ++ signature_alg = "sha1"; > ++ else if ((signature = find_commit_multiline_header(commit_buffer_cursor + 1, "gpgsig-sha256", &commit_buffer_cursor))) > ++ signature_alg = "sha256"; > ++ } > + > message = strstr(commit_buffer_cursor, "\n\n"); > if (message) > @@ builtin/fast-export.c: static void handle_commit(struct commit *commit, struct r > printf("%.*s\n%.*s\n", > (int)(author_end - author), author, > (int)(committer_end - committer), committer); > -+ if (signature) > -+ switch(signed_commit_mode) { > ++ if (signature) { > ++ switch (signed_commit_mode) { > + case SIGN_ABORT: > + die("encountered signed commit %s; use " > + "--signed-commits=<mode> to handle it", > @@ builtin/fast-export.c: static void handle_commit(struct commit *commit, struct r > + case SIGN_STRIP: > + break; > + } > ++ free((char *)signature); > ++ } > if (!reencoded && encoding) > printf("encoding %.*s\n", (int)encoding_len, encoding); > printf("data %u\n%s", > @@ builtin/fast-export.c: static void handle_tag(const char *name, struct tag *tag) > "\n-----BEGIN PGP SIGNATURE-----\n"); > if (signature) > - switch(signed_tag_mode) { > + switch (signed_tag_mode) { > - case SIGNED_TAG_ABORT: > + case SIGN_ABORT: > die("encountered signed tag %s; use " > @@ builtin/fast-export.c: static void handle_tag(const char *name, struct tag *tag) > message_size = signature + 1 - message; > break; > } > -@@ builtin/fast-export.c: static int parse_opt_anonymize_map(const struct option *opt, > - > - int cmd_fast_export(int argc, const char **argv, const char *prefix) > +@@ builtin/fast-export.c: int cmd_fast_export(int argc, > + const char *prefix, > + struct repository *repo UNUSED) > { > + const char *env_signed_commits_noabort; > struct rev_info revs; > - struct object_array commits = OBJECT_ARRAY_INIT; > struct commit *commit; > -@@ builtin/fast-export.c: int cmd_fast_export(int argc, const char **argv, const char *prefix) > + char *export_filename = NULL, > +@@ builtin/fast-export.c: int cmd_fast_export(int argc, > N_("show progress after <n> objects")), > OPT_CALLBACK(0, "signed-tags", &signed_tag_mode, N_("mode"), > N_("select handling of signed tags"), > @@ builtin/fast-export.c: int cmd_fast_export(int argc, const char **argv, const ch > OPT_CALLBACK(0, "tag-of-filtered-object", &tag_of_filtered_mode, N_("mode"), > N_("select handling of tags that tag filtered objects"), > parse_opt_tag_of_filtered_mode), > -@@ builtin/fast-export.c: int cmd_fast_export(int argc, const char **argv, const char *prefix) > +@@ builtin/fast-export.c: int cmd_fast_export(int argc, > if (argc == 1) > usage_with_options (fast_export_usage, options); > > @@ builtin/fast-import.c: static void parse_new_commit(const char *arg) > + strbuf_addstr(&new_data, "gpgsig-sha256 "); > + else > + die("Expected gpgsig algorithm sha1 or sha256, got %s", sig_alg); > -+ string_list_split_in_place(&siglines, sig.buf, '\n', -1); > ++ string_list_split_in_place(&siglines, sig.buf, "\n", -1); > + strbuf_add_separated_string_list(&new_data, "\n ", &siglines); > + strbuf_addch(&new_data, '\n'); > + } > @@ t/t9350-fast-export.sh: test_expect_success 'signed-tags=warn-strip' ' > + # between the two. > + test_config i18n.commitEncoding ISO-8859-1 && > + git checkout -f -b commit-signing main && > -+ echo Sign your name > file-sign && > ++ echo Sign your name >file-sign && > + git add file-sign && > + git commit -S -m "signed commit" && > + COMMIT_SIGNING=$(git rev-parse --verify commit-signing) > @@ t/t9350-fast-export.sh: test_expect_success 'signed-tags=warn-strip' ' > + > +test_expect_success GPG 'signed-commits default' ' > + > -+ unset FAST_EXPORT_SIGNED_COMMITS_NOABORT && > ++ sane_unset FAST_EXPORT_SIGNED_COMMITS_NOABORT && > + test_must_fail git fast-export --reencode=no commit-signing && > + > + FAST_EXPORT_SIGNED_COMMITS_NOABORT=1 git fast-export --reencode=no commit-signing >output 2>err && > + ! grep ^gpgsig output && > + grep "^encoding ISO-8859-1" output && > + test -s err && > -+ sed "s/commit-signing/commit-strip-signing/" output | > -+ (cd new && > -+ git fast-import && > -+ test $COMMIT_SIGNING != $(git rev-parse --verify refs/heads/commit-strip-signing)) > ++ sed "s/commit-signing/commit-strip-signing/" output | ( > ++ cd new && > ++ git fast-import && > ++ STRIPPED=$(git rev-parse --verify refs/heads/commit-strip-signing) && > ++ test $COMMIT_SIGNING != $STRIPPED > ++ ) > + > +' > + > @@ t/t9350-fast-export.sh: test_expect_success 'signed-tags=warn-strip' ' > + git fast-export --signed-commits=verbatim --reencode=no commit-signing >output && > + grep "^gpgsig sha" output && > + grep "encoding ISO-8859-1" output && > -+ (cd new && > -+ git fast-import && > -+ test $COMMIT_SIGNING = $(git rev-parse --verify refs/heads/commit-signing)) <output > ++ ( > ++ cd new && > ++ git fast-import && > ++ STRIPPED=$(git rev-parse --verify refs/heads/commit-signing) && > ++ test $COMMIT_SIGNING = $STRIPPED > ++ ) <output > + > +' > + > @@ t/t9350-fast-export.sh: test_expect_success 'signed-tags=warn-strip' ' > + grep "^gpgsig sha" output && > + grep "encoding ISO-8859-1" output && > + test -s err && > -+ (cd new && > -+ git fast-import && > -+ test $COMMIT_SIGNING = $(git rev-parse --verify refs/heads/commit-signing)) <output > ++ ( > ++ cd new && > ++ git fast-import && > ++ STRIPPED=$(git rev-parse --verify refs/heads/commit-signing) && > ++ test $COMMIT_SIGNING = $STRIPPED > ++ ) <output > + > +' > + > @@ t/t9350-fast-export.sh: test_expect_success 'signed-tags=warn-strip' ' > + git fast-export --signed-commits=strip --reencode=no commit-signing >output && > + ! grep ^gpgsig output && > + grep "^encoding ISO-8859-1" output && > -+ sed "s/commit-signing/commit-strip-signing/" output | > -+ (cd new && > -+ git fast-import && > -+ test $COMMIT_SIGNING != $(git rev-parse --verify refs/heads/commit-strip-signing)) > ++ sed "s/commit-signing/commit-strip-signing/" output | ( > ++ cd new && > ++ git fast-import && > ++ STRIPPED=$(git rev-parse --verify refs/heads/commit-strip-signing) && > ++ test $COMMIT_SIGNING != $STRIPPED > ++ ) > + > +' > + > @@ t/t9350-fast-export.sh: test_expect_success 'signed-tags=warn-strip' ' > + ! grep ^gpgsig output && > + grep "^encoding ISO-8859-1" output && > + test -s err && > -+ sed "s/commit-signing/commit-strip-signing/" output | > -+ (cd new && > -+ git fast-import && > -+ test $COMMIT_SIGNING != $(git rev-parse --verify refs/heads/commit-strip-signing)) > ++ sed "s/commit-signing/commit-strip-signing/" output | ( > ++ cd new && > ++ git fast-import && > ++ STRIPPED=$(git rev-parse --verify refs/heads/commit-strip-signing) && > ++ test $COMMIT_SIGNING != $STRIPPED > ++ ) > + > +' > + > test_expect_success 'setup submodule' ' > > + test_config_global protocol.file.allow always && > git checkout -f main && > -+ { git update-ref -d refs/heads/commit-signing || true; } && > ++ test_might_fail git update-ref -d refs/heads/commit-signing && > mkdir sub && > ( > cd sub && > > > Christian Couder (1): > fast-export: fix missing whitespace after switch > > Luke Shumaker (5): > git-fast-import.adoc: add missing LF in the BNF > fast-export: rename --signed-tags='warn' to 'warn-verbatim' > git-fast-export.txt: clarify why 'verbatim' may not be a good idea > fast-export: do not modify memory from get_commit_buffer > fast-export, fast-import: add support for signed-commits > > Documentation/git-fast-export.adoc | 25 +++- > Documentation/git-fast-import.adoc | 20 ++- > builtin/fast-export.c | 189 +++++++++++++++++++++-------- > builtin/fast-import.c | 23 ++++ > t/t9350-fast-export.sh | 116 ++++++++++++++++++ > 5 files changed, 317 insertions(+), 56 deletions(-) >
On Mon, Feb 24, 2025 at 11:51 PM Patrick Steinhardt <ps@pks.im> wrote: > > On Mon, Feb 24, 2025 at 11:35:00PM -0800, Elijah Newren wrote: > > On Mon, Feb 24, 2025 at 9:01 AM Junio C Hamano <gitster@pobox.com> wrote: > > > > > > Christian Couder <christian.couder@gmail.com> writes: > > > > > > > Luke Shumaker sent the first 4 versions of this series in April 2021, > > > > but it looks like he stopped before it got merged. Let's finish > > > > polishing it. > > > > > > Nice to see an old topic resurrected. > > > > > > > fast-export has an existing --signed-tags= option that controls how to > > > > handle tag signatures. However, there is no equivalent for commit > > > > signatures; it just silently strips the signature out of the commit > > > > (analogously to --signed-tags=strip). > > > > > > > > So implement a --signed-commits= flag in fast-export, and implement > > > > the receiving side of it in fast-import. > > > > > > Nice. > > > > > > I haven't thought about this topic obviously for a looooong time, > > > but I wonder we may want to have an option, which is independent > > > from these --signed-tags/--signed-commits options addressed here, > > > that allows the person who performed the import to attest to the > > > result by adding their own signature on tags and commits, whether > > > these tags and commits were originally signed or not. > > > > For what it's worth, this has been requested multiple times of > > git-filter-repo, so there is some desire for this feature. > > This is also exactly the usecase we have been reviving this effort for > :) We recently hit such a case where a customer was basically unable to > use git-filter-repo(1) due to commit signatures, so we wanted to help > out and get this patch series landed so that the issue can ultimately be > addressed in git-filter-repo(1). I'm confused; this patch series doesn't implement the option Junio and I were talking about. It only allows existing signatures to be carried as-is, as opposed to resigning all the commits with the current user's signature.
Elijah Newren <newren@gmail.com> writes: >> This is also exactly the usecase we have been reviving this effort for >> :) We recently hit such a case where a customer was basically unable to >> use git-filter-repo(1) due to commit signatures, so we wanted to help >> out and get this patch series landed so that the issue can ultimately be >> addressed in git-filter-repo(1). > > I'm confused; this patch series doesn't implement the option Junio and > I were talking about. It only allows existing signatures to be > carried as-is, as opposed to resigning all the commits with the > current user's signature. I read the "can ultimately be" as "this series lays the groundwork by upstreaming what the earlier effort started and stops there. a future follow-up work will build on this to add more".