* trailers: --only-trailers normalizes URLs to trailers @ 2026-06-04 21:27 Kristoffer Haugsbakk 2026-06-09 0:43 ` Jeff King 0 siblings, 1 reply; 11+ messages in thread From: Kristoffer Haugsbakk @ 2026-06-04 21:27 UTC (permalink / raw) To: git The following is a bug that follows straightforwardly from the documented or discussed behavior. In that sense it is not a bug. But it is a bug in the sense that it makes things inconvenient and violates a design goal. > Thank you for filling out a Git bug report! > Please answer the following questions to help us understand your issue. > > What did you do before the bug happened? (Steps to reproduce your issue) Ran what is the equivalent of git interpret-trailers --only-trailers With git log --format="%(trailers:only)" > What did you expect to happen? (Expected behavior) For URLs like https://www.digsm.xyz/ to be left intact. (Well, did I expect that? It follows from the discussed behavior...) > What happened instead? (Actual behavior) URLs on a line by themselves in eligible trailer blocks get normalized/canonicalized to a “trailer” with key e.g. `https`: https: //www.digsm.xyz/ > What's different between what you expected and what actually happened? In an ideal world to have some special-casing of URLs so that they are not detected as trailers. Does anyone realistically want trailers like this?: file: //... http: //... https: //... Maybe a C-style comment? https: // I changed my mind about providing a URL here. This comment is a placeholder. Comment: // But next up we have a URL https: https://protocoltwiceover.net And this is where my imagination ends. Just special-casing `https` would go a long way. > Anything else you want to add: Yes, after this [System Info] part. > Please review the rest of the bug report below. > You can delete any lines you don't wish to share. [System Info] git version: git version 2.54.0 cpu: x86_64 built from commit: 94f057755b7941b321fd11fec1b2e3ca5313a4e0 sizeof-long: 8 sizeof-size_t: 8 shell-path: /bin/sh rust: disabled gettext: enabled libcurl: 7.81.0 OpenSSL: OpenSSL 3.0.2 15 Mar 2022 zlib: 1.2.11 SHA-1: SHA1_DC SHA-256: SHA256_BLK default-ref-format: files default-hash: sha1 uname: Linux 6.8.0-117-generic #117~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Thu May 7 22:17:46 UTC x86_64 compiler info: gnuc: 11.4 libc info: glibc: 2.35 $SHELL (typically, interactive shell): /bin/bash [Enabled Hooks] commit-msg post-applypatch post-commit sendemail-validate *** That things like `--format='%(trailers:only)'` normalize trailers is known and has been discussed before.[1] There’s been discussion around the key capitalization and prefix normalization. But this is not about that. This is just about normalizing the separator part. 🔗 1: https://lore.kernel.org/git/87blk0rjob.fsf@0x63.nu/ One design goal for trailers (either by implementers or reviewers or both) has been to avoid false positives.[2] That meant trying to avoid detecting trailers that were not intended. For example: Everything was better in the past. Let me not even start on this rant: it is not good for my blood pressure. This will not be picked up as a trailer block unless `rant` is configured as a trailer key. † 2: See e.g. Jonathan Tan’s series about among other things adding the 25% rule https://lore.kernel.org/git/xmqq7f96sa9i.fsf@gitster.mtv.corp.google.com/ But that’s pretty innocuous. Just a misplaced rant. The topic of this bug report is not a big deal either, but it is: 1. Structured data that gets mangled in this normalize mode 2. That can naturally go at the end of the message on its own line And these two points are very relevant for people who never use trailers. Or, wait. I guess it isn’t if they don’t use trailers and thus will never normalize them. But it is relevant if they work on a project where someone else does that. IN INTENDED TRAILER BLOCKS [3] And then there are things that can go wrong if you intend to write trailer blocks: 1. “Non-trailer lines” that are URLs get normalized as trailers (NTL for short) 2. User error line wrapping turns one trailer into an empty trailer plus a `https` trailer (LW for short) 3. Normalizing trailers along the way (as in patches in flight or something) introduces this strange lossiness (NL for short) I did (2) (LW for short) four years ago it seems: See: https://digsm.yxz/blog/important-context/?bigtechtracker=86b0c5a1e2b73b08fd54c727f4458649ed9fe3ad1b6e8ac9460c070113509a1e † 3: Are all-caps titles good or bad? Let me know. IN THE LINUX KERNEL There are some hits for the `http` and `https` trailers when trailers are normalized. The baseline: $ git log --extended-regexp --grep='https?: //' --oneline | wc -l 12 With normalization: $ git log --format='%(trailers:only)' | grep --extended-regexp '^https?: //' | wc -l 245 Note that I have no idea how the Linux Kernel is run. But I don’t imagine that there are uses for `https: //...` trailers. And trailer usage is complicated. There are for example on-purpose indented `Link` “trailers”, presumably for the purpose of *excluding* them as `Link` trailers. See: commit d80a9cb1a64ab9c817b6262c7e4e433b6a3581a0 <body> [ljs@kernel.org: avoid bisection hazard] Link: https://lkml.kernel.org/r/d0cc6161-77a4-42ba-a411-96c23c78df1b@lucifer.local Link: https://lkml.kernel.org/r/c2be872d64ef9573b80727d9ab5446cf002f17b5.1774029655.git.ljs@kernel.org Signed-off-by: Lorenzo Stoakes (Oracle) <ljs@kernel.org> [MORE BELOW] Is that indented link for that `[]` comment? I dunno. But what’s the main topic here are intended non-trailer lines which are URLs that get treated as trailers (NTL). Like this invented example: Reported-by: ... https://digsm.xyz/?avastvirus=5891b5b522d5df086d0ff0b110fbd9d21bb4fc7163af34d08286a2e846f6be03 Signed-off-by: ... Or this real example where the URLs are clearly part of a “comment” non-trailer run. 8236fc613d44e59f6736d6c3e9efffaf26ab7f00 Signed-off-by: Shuai Xue <xueshuai@linux.alibaba.com> [bhelgaas: squash fixes: https://lore.kernel.org/r/20260108013956.14351-2-bagasdotme@gmail.com https://lore.kernel.org/r/20260108013956.14351-3-bagasdotme@gmail.com] Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> Link: https://patch.msgid.link/20251210132907.58799-4-xueshuai@linux.alibaba.com (These are shown as they are written in the commit message. Normalizing the messages would create `https` trailers.) Here are examples of line-wrapping mistake commits (LW) for `Link`, `Closes`, or `Fixes` (sometimes these point to bug URLs and not commits): 5bd97f5c5f241a5610c4412d1b93995a26241f81 Link: https://patch.msgid.link/20260216-work-xattr-socket-v1-4-c2efa4f74cb7@kernel.org Link: https://lore.kernel.org/3cnmtqmakpbb2uwhenrj7kdqu3uefykiykjllgfbtpkiwhaa4s@sghkevv7jned [1] Acked-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Jan Kara <jack@suse.cz> Signed-off-by: Christian Brauner <brauner@kernel.org> and: • 24abe1f238e7d7ac56be6374c52a3c13dab84f69 • 27e21516914dc130a79aa895a5a26e18f0213a5a • be3536a4bdda53ff5a91b7e542b167d12bddb317 Finally there is this commit which has a trailer in the commit message itself with the key `https` (NL). commit 496c0c4c53bbe1bad97e82cd12103df61a6e459d ... ... net: wan: fsl_ucc_hdlc: free tx_skbuff in uhdlc_memclean <body> https: //sashiko.dev/#/patchset/20260429114208.941011-1-holger.brunck%40hitachienergy.com Fixes: c19b6d246a35 ("drivers/net: support hdlc function for QE-UCC") Signed-off-by: Holger Brunck <holger.brunck@hitachienergy.com> Link: https://patch.msgid.link/20260507155332.3452319-1-holger.brunck@hitachienergy.com Signed-off-by: Jakub Kicinski <kuba@kernel.org> How could this have happened? Follow the patch-id link. https://patch.msgid.link/20260507155332.3452319-1-holger.brunck@hitachienergy.com https://sashiko.dev/#/patchset/20260429114208.941011-1-holger.brunck%40hitachienergy.com Fixes: c19b6d246a35 ("drivers/net: support hdlc function for QE-UCC") Signed-off-by: Holger Brunck <holger.brunck@hitachienergy.com> So it was just a non-trailer URL line as this person submitted it. But presumably the person who applied it put the message through a round of normalization. Cheers, good night -- Kristoffer ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: trailers: --only-trailers normalizes URLs to trailers 2026-06-04 21:27 trailers: --only-trailers normalizes URLs to trailers Kristoffer Haugsbakk @ 2026-06-09 0:43 ` Jeff King 2026-06-10 14:21 ` Kristoffer Haugsbakk 2026-08-02 19:57 ` [PATCH] trailers: stop recognizing URLs as trailers kristofferhaugsbakk 0 siblings, 2 replies; 11+ messages in thread From: Jeff King @ 2026-06-09 0:43 UTC (permalink / raw) To: Kristoffer Haugsbakk; +Cc: git On Thu, Jun 04, 2026 at 11:27:51PM +0200, Kristoffer Haugsbakk wrote: > The following is a bug that follows straightforwardly from the documented > or discussed behavior. In that sense it is not a bug. But it is a bug in > the sense that it makes things inconvenient and violates a design goal. Yeah, though if you'll allow me to nitpick your subject a moment: I don't think --only-trailers is really the culprit here. It demonstrates the problem because it normalizes the "trailer" it found. But the loose trailer matching is the more fundamental issue. For example: git interpret-trailers --trailer=foo=bar <<\EOF subject body http://example.com EOF will stick the new "foo: bar" trailer right up against the (now-broken) "http:" trailer. When it should come in its own stanza, which it would if you added a line "other" at the end, since that tells us that "http:" can't be a trailer. > > What's different between what you expected and what actually happened? > > In an ideal world to have some special-casing of URLs so that they are > not detected as trailers. Does anyone realistically want trailers like > this?: > > file: //... > http: //... > https: //... I could even see those as trailers, if somebody really wanted to allow arbitrary values that might just happen to start with "//". But without the whitespace after the colon, it is quite questionable. > Just special-casing `https` would go a long way. Agreed, though I think a rule like: ":// (with no whitespace)" is not a valid separator. Something like this: diff --git a/trailer.c b/trailer.c index 6d8ec7fa8d..342ed81c78 100644 --- a/trailer.c +++ b/trailer.c @@ -635,8 +635,12 @@ static ssize_t find_separator(const char *line, const char *separators) int whitespace_found = 0; const char *c; for (c = line; *c; c++) { - if (strchr(separators, *c)) + if (strchr(separators, *c)) { + /* special case to avoid accidental URL matches */ + if (*c == ':' && c[1] == '/' && c[2] == '/') + return -1; return c - line; + } if (!whitespace_found && (isalnum(*c) || *c == '-')) continue; if (c != line && (*c == ' ' || *c == '\t')) { -Peff ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: trailers: --only-trailers normalizes URLs to trailers 2026-06-09 0:43 ` Jeff King @ 2026-06-10 14:21 ` Kristoffer Haugsbakk 2026-06-11 6:56 ` Jeff King 2026-08-02 19:57 ` [PATCH] trailers: stop recognizing URLs as trailers kristofferhaugsbakk 1 sibling, 1 reply; 11+ messages in thread From: Kristoffer Haugsbakk @ 2026-06-10 14:21 UTC (permalink / raw) To: Jeff King; +Cc: git On Tue, Jun 9, 2026, at 02:43, Jeff King wrote: > On Thu, Jun 04, 2026 at 11:27:51PM +0200, Kristoffer Haugsbakk wrote: > >> The following is a bug that follows straightforwardly from the documented >> or discussed behavior. In that sense it is not a bug. But it is a bug in >> the sense that it makes things inconvenient and violates a design goal. > > Yeah, though if you'll allow me to nitpick your subject a moment: I > don't think --only-trailers is really the culprit here. It demonstrates > the problem because it normalizes the "trailer" it found. But the loose > trailer matching is the more fundamental issue. For example: > >[snip] Yeah, this is more precise. I focused a ton on the normalized output because that’s what makes it obvious. But the fundamental problem is interpreting URLs like trailers. > >> > What's different between what you expected and what actually happened? >> >> In an ideal world to have some special-casing of URLs so that they are >> not detected as trailers. Does anyone realistically want trailers like >> this?: >> >> file: //... >> http: //... >> https: //... > > I could even see those as trailers, if somebody really wanted to allow > arbitrary values that might just happen to start with "//". But without > the whitespace after the colon, it is quite questionable. > >> Just special-casing `https` would go a long way. > > Agreed, though I think a rule like: ":// (with no whitespace)" is not a > valid separator. Something like this: Yes, matching on `://` strictly is a better proposal. No need to care about `http`, `https`, `file`, etc. And both of these would *still* have to be true for this change to be a false negative w.r.t. the user’s intentions: • They really input a trailer that looks like a URL, but it’s not meant to be a URL • They really wanted the value to start with `//` And again I don’t think that is likely to ever happen (with a knock on wood). Thanks! > > diff --git a/trailer.c b/trailer.c > index 6d8ec7fa8d..342ed81c78 100644 > --- a/trailer.c > +++ b/trailer.c > @@ -635,8 +635,12 @@ static ssize_t find_separator(const char *line, > const char *separators) > int whitespace_found = 0; > const char *c; > for (c = line; *c; c++) { > - if (strchr(separators, *c)) > + if (strchr(separators, *c)) { > + /* special case to avoid accidental URL matches */ > + if (*c == ':' && c[1] == '/' && c[2] == '/') > + return -1; > return c - line; > + } > if (!whitespace_found && (isalnum(*c) || *c == '-')) > continue; > if (c != line && (*c == ' ' || *c == '\t')) { ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: trailers: --only-trailers normalizes URLs to trailers 2026-06-10 14:21 ` Kristoffer Haugsbakk @ 2026-06-11 6:56 ` Jeff King 2026-06-11 7:03 ` Kristoffer Haugsbakk 0 siblings, 1 reply; 11+ messages in thread From: Jeff King @ 2026-06-11 6:56 UTC (permalink / raw) To: Kristoffer Haugsbakk; +Cc: git On Wed, Jun 10, 2026 at 04:21:29PM +0200, Kristoffer Haugsbakk wrote: > > Yeah, though if you'll allow me to nitpick your subject a moment: I > > don't think --only-trailers is really the culprit here. It demonstrates > > the problem because it normalizes the "trailer" it found. But the loose > > trailer matching is the more fundamental issue. For example: > > > >[snip] > > Yeah, this is more precise. I focused a ton on the normalized output > because that’s what makes it obvious. But the fundamental problem is > interpreting URLs like trailers. That makes sense. As the author of --only-trailers I immediately wondered if I had introduced a bug in it, so I was partially motivated by exonerating myself. ;) I agree that using it is the simplest way to demonstrate the problem. > > Agreed, though I think a rule like: ":// (with no whitespace)" is not a > > valid separator. Something like this: > > Yes, matching on `://` strictly is a better proposal. No need to care > about `http`, `https`, `file`, etc. And both of these would *still* have > to be true for this change to be a false negative w.r.t. the user’s > intentions: > > • They really input a trailer that looks like a URL, but it’s not meant > to be a URL > • They really wanted the value to start with `//` > > And again I don’t think that is likely to ever happen (with a knock > on wood). I didn't spend much effort on the patch I showed beyond running it once. It would probably need tests and a doc update. I wasn't planning to run with it, but if you feel like doing so, please feel free to use it as you like. -Peff ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: trailers: --only-trailers normalizes URLs to trailers 2026-06-11 6:56 ` Jeff King @ 2026-06-11 7:03 ` Kristoffer Haugsbakk 0 siblings, 0 replies; 11+ messages in thread From: Kristoffer Haugsbakk @ 2026-06-11 7:03 UTC (permalink / raw) To: Jeff King; +Cc: git On Thu, Jun 11, 2026, at 08:56, Jeff King wrote: >>[snip] >> >> And again I don’t think that is likely to ever happen (with a knock >> on wood). > > I didn't spend much effort on the patch I showed beyond running it once. > It would probably need tests and a doc update. I wasn't planning to run > with it, but if you feel like doing so, please feel free to use it as > you like. Yeah, I want to add some tests on top and make a sumbission (but sent a message to first confirm that you weren't cooking anything more ;) ). Thanks. -- Sent from mobile ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH] trailers: stop recognizing URLs as trailers 2026-06-09 0:43 ` Jeff King 2026-06-10 14:21 ` Kristoffer Haugsbakk @ 2026-08-02 19:57 ` kristofferhaugsbakk 2026-08-02 22:36 ` Junio C Hamano 2026-08-03 15:20 ` Jeff King 1 sibling, 2 replies; 11+ messages in thread From: kristofferhaugsbakk @ 2026-08-02 19:57 UTC (permalink / raw) To: git; +Cc: Kristoffer Haugsbakk, Jeff King From: Kristoffer Haugsbakk <code@khaugsbakk.name> An HTTPS URL starts with an alphanumeric scheme followed by a colon. That means that they will be recognized as trailers in a trailer block. That turns out to be a problem in practice. Let’s stop recognizing these as trailers by failing the trailer parsing when we: 1. find the separator; 2. the separator and the next two characters form `://`; and 3. we haven’t parsed any whitespace yet. The simplest example of how this can be a problem is for people who do not use trailers but may leave URLs at the end of the commit message. Now, while these authors might not use trailers themselves, other authors may have used trailers and this metadata confusion can become a problem once someone tries to extract that metadata (and non-metadata). Let’s now look at some examples in the Linux Kernel[1] to see how this is a problem in practice. There are commits which contain intended non-trailer lines which start with URLs. These are comments. Example with just the trailers:[2] Signed-off-by: Shuai Xue <xueshuai@linux.alibaba.com> [bhelgaas: squash fixes: https://lore.kernel.org/r/20260108013956.14351-2-bagasdotme@gmail.com https://lore.kernel.org/r/20260108013956.14351-3-bagasdotme@gmail.com] Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> Link: https://patch.msgid.link/20251210132907.58799-4-xueshuai@linux.alibaba.com Those `[]` pairs delimit the “squash fixes” comment. Now, any of these two commands: git log --format='%(trailers:only)' -1 <commit> git log -1 --format=%B <commit> | git interpret-trailers --only-trailers Will both wrongly (according to the surmised user intent) include these two URL lines as trailers and also mangle the URLs, e.g.: https: //lore.kernel.org/r/20260108013956.14351-2-bagasdotme@gmail.com Because the `--only-trailers` mode (or `only` for the git-log(1) format) normalizes the output to a colon and a space. Another example is linewrapping mistakes; a `Link` trailer with a URL where the URL ended up on the next line, presumably because the user’s editor linewrapped the “too long” line. Example with just the trailers:[3] Link: https://patch.msgid.link/20260216-work-xattr-socket-v1-4-c2efa4f74cb7@kernel.org Link: https://lore.kernel.org/3cnmtqmakpbb2uwhenrj7kdqu3uefykiykjllgfbtpkiwhaa4s@sghkevv7jned [1] Acked-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Jan Kara <jack@suse.cz> Signed-off-by: Christian Brauner <brauner@kernel.org> Now, this intended trailer is already ruined, but interpreting the URL as a standalone trailer only compounds the mistake. Yet another example is the trailer machinery normalizing the trailer block before application, resulting in a `https` trailer key in the commit message itself. Example with just the trailers:[4] https: //sashiko.dev/#/patchset/20260429114208.941011-1-holger.brunck%40hitachienergy.com Fixes: c19b6d246a35 ("drivers/net: support hdlc function for QE-UCC") Signed-off-by: Holger Brunck <holger.brunck@hitachienergy.com> Link: https://patch.msgid.link/20260507155332.3452319-1-holger.brunck@hitachienergy.com Signed-off-by: Jakub Kicinski <kuba@kernel.org> We have a helpful `Link` that points to the original patch.[5] Following it we can see that that `https` trailer was indeed a URL originally (again just the trailer block here): https://sashiko.dev/#/patchset/20260429114208.941011-1-holger.brunck%40hitachienergy.com Fixes: c19b6d246a35 ("drivers/net: support hdlc function for QE-UCC") Signed-off-by: Holger Brunck <holger.brunck@hitachienergy.com> So how did it end up as a `https` trailer? My theory is that the trailer block was normalized on patch application, causing a URL comment to be wrongly normalized and cemented in the commit message as a trailer.[6] † 1: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/ † 2: commit 8236fc613d44e59f6736d6c3e9efffaf26ab7f00 † 3: commit 5bd97f5c5f241a5610c4412d1b93995a26241f81 † 4: commit 496c0c4c53bbe1bad97e82cd12103df61a6e459d † 5: https://patch.msgid.link/20260507155332.3452319-1-holger.brunck@hitachienergy.com † 6: There are only four commits in the Linux Kernel of this kind, and three of them have the same recurring person in the signoff chain. Helped-by: Jeff King <peff@peff.net> Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name> --- Notes (series): Topic name: trailers-no-urls Topic summary: Stop recognizing URLs in trailer blocks as trailers. Note to the maintainer: this is based on `master` with topic kh/doc-trailers merged into it. I used Peff’s suggestion from the previous email. I just shortened the comment, added the parentheses (://) and added the condition that whitespace has not been found for the case I discussed of someone writing out `<key>: //` (note the space). (Or for that matter: `<key> ://`.) I can’t imagine that that is a likely case, but I just want to avoid matching URLs, so we don’t have to reject this case. t/u-trailer.c: `expected_contents[]` is not formatted like the other ones in this file. But this is what clang-format(1) gave me. Documentation/git-interpret-trailers.adoc | 13 ++++-- t/t7513-interpret-trailers.sh | 19 +++++++++ t/unit-tests/u-trailer.c | 52 +++++++++++++++++++++++ trailer.c | 7 ++- 4 files changed, 87 insertions(+), 4 deletions(-) diff --git a/Documentation/git-interpret-trailers.adoc b/Documentation/git-interpret-trailers.adoc index b4988d39eab..903d598dcb0 100644 --- a/Documentation/git-interpret-trailers.adoc +++ b/Documentation/git-interpret-trailers.adoc @@ -123,9 +123,16 @@ OTHER RULES What was covered in the previous section are the rules that are relevant for regular use. The following points are included for completeness. -This command ignores comment lines (see `core.commentString` in -linkgit:git-config[1]). This is for use with the `prepare-commit-msg` -and `commit-msg` hooks. +-- +* This command ignores comment lines (see `core.commentString` in + linkgit:git-config[1]). This is for use with the `prepare-commit-msg` + and `commit-msg` hooks. + +* Candidate trailer lines that have `:` as the separator, that have no + whitespace before the value part, and that start with `//` are not + recognized as trailers. This is to avoid accidentally interpreting + URLs as trailers (e.g. lines that start with `https://`). +-- OPTIONS ------- diff --git a/t/t7513-interpret-trailers.sh b/t/t7513-interpret-trailers.sh index 818a8dafbd2..e3555b6d51d 100755 --- a/t/t7513-interpret-trailers.sh +++ b/t/t7513-interpret-trailers.sh @@ -1989,4 +1989,23 @@ test_expect_success 'handling of --- lines in conjunction with cut-lines' ' test_cmp expected actual ' +test_expect_success 'URLs and lines that are not quite URLs' ' + cat >expect <<-\EOF && + https: //www.a-trailer.org + https: //www.another-trailer.org + Signed-off-by: somebody <somebody@somewhere> + EOF + git interpret-trailers --only-trailers >actual <<-\EOF && + subject + + body + + https://www.not-a-trailer.org + https ://www.a-trailer.org + https: //www.another-trailer.org + Signed-off-by: somebody <somebody@somewhere> + EOF + test_cmp expect actual +' + test_done diff --git a/t/unit-tests/u-trailer.c b/t/unit-tests/u-trailer.c index 3d60ea1603d..7404b165fac 100644 --- a/t/unit-tests/u-trailer.c +++ b/t/unit-tests/u-trailer.c @@ -318,3 +318,55 @@ void test_trailer__one_non_trailer_no_git_trailers(void) 0, expected_contents); } + +void test_trailer__URL(void) +{ + struct contents expected_contents[] = { 0 }; + + t_trailer_iterator("Subject: foo bar\n" + "\n" + /* + * We do not want to match URLs as trailers. + */ + "https://www.example.org\n", + 0, + expected_contents); +} + +void test_trailer__not_a_URL_space_after_separator(void) +{ + struct contents expected_contents[] = { + { .raw = "https: //www.example.org\n", + .key = "https", + .val = "//www.example.org" }, + { 0 }, + }; + + t_trailer_iterator("Subject: foo bar\n" + "\n" + /* + * This has a space after ':' so it's not a URL. + */ + "https: //www.example.org\n", + 1, + expected_contents); +} + +void test_trailer__not_a_URL_space_before_separator(void) +{ + struct contents expected_contents[] = { + { .raw = "https ://www.example.org\n", + .key = "https", + .val = "//www.example.org" }, + { 0 }, + }; + + t_trailer_iterator("Subject: foo bar\n" + "\n" + /* + * This has a space before ':' so it's not a URL. + */ + "https ://www.example.org\n", + 1, + expected_contents); +} diff --git a/trailer.c b/trailer.c index 6d8ec7fa8d8..971ae459596 100644 --- a/trailer.c +++ b/trailer.c @@ -635,8 +635,13 @@ static ssize_t find_separator(const char *line, const char *separators) int whitespace_found = 0; const char *c; for (c = line; *c; c++) { - if (strchr(separators, *c)) + if (strchr(separators, *c)) { + /* avoid accidental URL matches (://) */ + if (*c == ':' && c[1] == '/' && c[2] == '/' && + !whitespace_found) + return -1; return c - line; + } if (!whitespace_found && (isalnum(*c) || *c == '-')) continue; if (c != line && (*c == ' ' || *c == '\t')) { -- 2.54.0.22.g9e26862b904 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH] trailers: stop recognizing URLs as trailers 2026-08-02 19:57 ` [PATCH] trailers: stop recognizing URLs as trailers kristofferhaugsbakk @ 2026-08-02 22:36 ` Junio C Hamano 2026-08-03 12:11 ` Kristoffer Haugsbakk 2026-08-03 15:20 ` Jeff King 1 sibling, 1 reply; 11+ messages in thread From: Junio C Hamano @ 2026-08-02 22:36 UTC (permalink / raw) To: kristofferhaugsbakk; +Cc: git, Kristoffer Haugsbakk, Jeff King kristofferhaugsbakk@fastmail.com writes: > From: Kristoffer Haugsbakk <code@khaugsbakk.name> > > An HTTPS URL starts with an alphanumeric scheme followed by a colon. > That means that they will be recognized as trailers in a trailer block. > That turns out to be a problem in practice. Let’s stop recognizing these > as trailers by failing the trailer parsing when we: > > 1. find the separator; > 2. the separator and the next two characters form `://`; and > 3. we haven’t parsed any whitespace yet. When I read the problem description, I would have expected you to say "If we find <token>: at the beginning of the line, check <token> against known URL schemes like https, ftp, etc. and declare that the line is not a trailer, if it matches". Checking against "://" is much more robust, as it is less likely to happen in random text, and we avoid maintaining a whitelist of scheme names. You are certainly smarter than I am ;-). Shouldn't we restrict the token preceding "://" more strictly than simply prohibiting whitespace? > Helped-by: Jeff King <peff@peff.net> > Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name> > --- > diff --git a/trailer.c b/trailer.c > index 6d8ec7fa8d8..971ae459596 100644 > --- a/trailer.c > +++ b/trailer.c > @@ -635,8 +635,13 @@ static ssize_t find_separator(const char *line, const char *separators) > int whitespace_found = 0; > const char *c; > for (c = line; *c; c++) { > - if (strchr(separators, *c)) > + if (strchr(separators, *c)) { > + /* avoid accidental URL matches (://) */ > + if (*c == ':' && c[1] == '/' && c[2] == '/' && How do we know the references to c[1] and c[2] do not access an unmapped piece of memory? The answer is that line[] is NUL terminated, so c[0] == ':' guarantees that c[1] is safe to read and unless it is NUL (and c[1] =='/' certainly means it is not NUL), c[2] is safe to read. OK. Makes sense to me. Thanks. > + !whitespace_found) > + return -1; > return c - line; > + } > if (!whitespace_found && (isalnum(*c) || *c == '-')) > continue; > if (c != line && (*c == ' ' || *c == '\t')) { ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] trailers: stop recognizing URLs as trailers 2026-08-02 22:36 ` Junio C Hamano @ 2026-08-03 12:11 ` Kristoffer Haugsbakk 0 siblings, 0 replies; 11+ messages in thread From: Kristoffer Haugsbakk @ 2026-08-03 12:11 UTC (permalink / raw) To: Junio C Hamano; +Cc: git, Kristoffer Haugsbakk, Jeff King On Mon, Aug 3, 2026, at 00:36, Junio C Hamano wrote: > kristofferhaugsbakk@fastmail.com writes: > >> From: Kristoffer Haugsbakk <code@khaugsbakk.name> >> >> An HTTPS URL starts with an alphanumeric scheme followed by a colon. >> That means that they will be recognized as trailers in a trailer block. >> That turns out to be a problem in practice. Let’s stop recognizing these >> as trailers by failing the trailer parsing when we: >> >> 1. find the separator; >> 2. the separator and the next two characters form `://`; and >> 3. we haven’t parsed any whitespace yet. > > When I read the problem description, I would have expected you to > say "If we find <token>: at the beginning of the line, check <token> > against known URL schemes like https, ftp, etc. and declare that the > line is not a trailer, if it matches". Checking against "://" is > much more robust, as it is less likely to happen in random text, and > we avoid maintaining a whitelist of scheme names. You are certainly > smarter than I am ;-). The credit for being smart goes to Peff. https://lore.kernel.org/git/20260609004340.GF358144@coredump.intra.peff.net/T/#m03ac1a456648090c04cdf5141b7a3e638f1213d1 > Shouldn't we restrict the token preceding "://" more strictly than > simply prohibiting whitespace? Right now (with this code) we know that: 1. We have either parsed only alphanumerics and hyphens (whitespace is ruled out); or 2. We haven’t even parsed (1), but just found a line that starts with `://`. In both cases we bail out of the parsing with `-1`, i.e. “not a trailer”. Wikipedia[1] tells me that this current check *does* have a false positive: A non-empty scheme component followed by a colon (:), consisting of a sequence of characters beginning with a letter and followed by any combination of letters, digits, plus (+), period (.), or hyphen (-). 🔗 1: https://en.wikipedia.org/wiki/Uniform_Resource_Identifier#Syntax A URL *must* begin with a letter, but a trailer can just be a digit. Which means that this is not the start of a URL: 1:// But the current code will reject it as a URL. There are also other false positives like the strange but legal trailer key `-`. Other than that, the character set of trailers (alphanums and hyphens) is a strict subset of URL <scheme>. I also see that the git-interpret-trailers(1) doc update should say alphanumerics and/or hyphens instead of just alphanums. > >> Helped-by: Jeff King <peff@peff.net> >> Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name> >> --- > >> diff --git a/trailer.c b/trailer.c >> index 6d8ec7fa8d8..971ae459596 100644 >> --- a/trailer.c >> +++ b/trailer.c >> @@ -635,8 +635,13 @@ static ssize_t find_separator(const char *line, const char *separators) >> int whitespace_found = 0; >> const char *c; >> for (c = line; *c; c++) { >> - if (strchr(separators, *c)) >> + if (strchr(separators, *c)) { >> + /* avoid accidental URL matches (://) */ >> + if (*c == ':' && c[1] == '/' && c[2] == '/' && > > How do we know the references to c[1] and c[2] do not access an > unmapped piece of memory? The answer is that line[] is NUL > terminated, so c[0] == ':' guarantees that c[1] is safe to read and > unless it is NUL (and c[1] =='/' certainly means it is not NUL), > c[2] is safe to read. > > OK. Makes sense to me. I’m mostly a Java programmer so I had the same thought (non-didactically ;) ). Yes, because of sentinel `NUL` and boolean short-circuiting we can incrementally peak one character ahead. This would be wrong in any language without `NUL` terminating strings, but here it is correct. Indeed, checking the length first (which you would need to do in Java) would incur a linear cost since you need to scan the string until you hit the `NUL` terminator. > > Thanks. >[snip] ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] trailers: stop recognizing URLs as trailers 2026-08-02 19:57 ` [PATCH] trailers: stop recognizing URLs as trailers kristofferhaugsbakk 2026-08-02 22:36 ` Junio C Hamano @ 2026-08-03 15:20 ` Jeff King 2026-08-03 15:39 ` Junio C Hamano 2026-08-06 20:17 ` Kristoffer Haugsbakk 1 sibling, 2 replies; 11+ messages in thread From: Jeff King @ 2026-08-03 15:20 UTC (permalink / raw) To: kristofferhaugsbakk; +Cc: Junio C Hamano, git, Kristoffer Haugsbakk On Sun, Aug 02, 2026 at 09:57:17PM +0200, kristofferhaugsbakk@fastmail.com wrote: > There are commits which contain intended non-trailer lines which start > with URLs. These are comments. Example with just the trailers:[2] > > Signed-off-by: Shuai Xue <xueshuai@linux.alibaba.com> > [bhelgaas: squash fixes: > https://lore.kernel.org/r/20260108013956.14351-2-bagasdotme@gmail.com > https://lore.kernel.org/r/20260108013956.14351-3-bagasdotme@gmail.com] > Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> > Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> > Link: https://patch.msgid.link/20251210132907.58799-4-xueshuai@linux.alibaba.com > > Those `[]` pairs delimit the “squash fixes” comment. This example makes me wonder if we ought to be smarter about brackets. I.e., could/should we realize that the opening bracket is a comment and then ignore everything up to the closing one? That would help this case and other weird cases like: Signed-off-by: whomever [peff: there's a really interesting thing going on here: the comment is free-form text that happens to use a colon in a sentence, but we'll interpret it as a trailer with key "here"] Signed-off-by: another unlucky soul That said, I think there are cases without brackets that are also confusing. Like: Let me finish this commit message by telling you all about this amazing url: https://example.com So I don't think that is a counter-argument against this URL false-positive check, but just a possible direction for future exploration. > Another example is linewrapping mistakes; a `Link` trailer with a > URL where the URL ended up on the next line, presumably because the > user’s editor linewrapped the “too long” line. Example with just the > trailers:[3] > > Link: https://patch.msgid.link/20260216-work-xattr-socket-v1-4-c2efa4f74cb7@kernel.org > Link: > https://lore.kernel.org/3cnmtqmakpbb2uwhenrj7kdqu3uefykiykjllgfbtpkiwhaa4s@sghkevv7jned [1] > Acked-by: Darrick J. Wong <djwong@kernel.org> > Reviewed-by: Jan Kara <jack@suse.cz> > Signed-off-by: Christian Brauner <brauner@kernel.org> > > Now, this intended trailer is already ruined, but interpreting the URL > as a standalone trailer only compounds the mistake. Yeah, this is another interesting example. I agree it is fundamentally broken, but showing the "https" trailer is just making it worse. > diff --git a/trailer.c b/trailer.c > index 6d8ec7fa8d8..971ae459596 100644 > --- a/trailer.c > +++ b/trailer.c > @@ -635,8 +635,13 @@ static ssize_t find_separator(const char *line, const char *separators) > int whitespace_found = 0; > const char *c; > for (c = line; *c; c++) { > - if (strchr(separators, *c)) > + if (strchr(separators, *c)) { > + /* avoid accidental URL matches (://) */ > + if (*c == ':' && c[1] == '/' && c[2] == '/' && > + !whitespace_found) > + return -1; > return c - line; > + } As discussed elsewhere, we are free to match with short-circuiting because of the NUL termination. But that also means we could write this as: if (starts_with(c, "://") && !whitespace_found) which is perhaps a little more readable. -Peff ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] trailers: stop recognizing URLs as trailers 2026-08-03 15:20 ` Jeff King @ 2026-08-03 15:39 ` Junio C Hamano 2026-08-06 20:17 ` Kristoffer Haugsbakk 1 sibling, 0 replies; 11+ messages in thread From: Junio C Hamano @ 2026-08-03 15:39 UTC (permalink / raw) To: Jeff King; +Cc: kristofferhaugsbakk, git, Kristoffer Haugsbakk Jeff King <peff@peff.net> writes: > As discussed elsewhere, we are free to match with short-circuiting > because of the NUL termination. But that also means we could write this > as: > > if (starts_with(c, "://") && !whitespace_found) > > which is perhaps a little more readable. "little more" -> "much more" ;-). ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] trailers: stop recognizing URLs as trailers 2026-08-03 15:20 ` Jeff King 2026-08-03 15:39 ` Junio C Hamano @ 2026-08-06 20:17 ` Kristoffer Haugsbakk 1 sibling, 0 replies; 11+ messages in thread From: Kristoffer Haugsbakk @ 2026-08-06 20:17 UTC (permalink / raw) To: Jeff King; +Cc: Junio C Hamano, git On Mon, Aug 3, 2026, at 17:20, Jeff King wrote: > On Sun, Aug 02, 2026 at 09:57:17PM +0200, > kristofferhaugsbakk@fastmail.com wrote: > >> There are commits which contain intended non-trailer lines which start >> with URLs. These are comments. Example with just the trailers:[2] >> >> Signed-off-by: Shuai Xue <xueshuai@linux.alibaba.com> >> [bhelgaas: squash fixes: >> https://lore.kernel.org/r/20260108013956.14351-2-bagasdotme@gmail.com >> https://lore.kernel.org/r/20260108013956.14351-3-bagasdotme@gmail.com] >> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> >> Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> >> Link: https://patch.msgid.link/20251210132907.58799-4-xueshuai@linux.alibaba.com >> >> Those `[]` pairs delimit the “squash fixes” comment. > > This example makes me wonder if we ought to be smarter about brackets. > I.e., could/should we realize that the opening bracket is a comment and > then ignore everything up to the closing one? That would help this case > and other weird cases like: [snip] I think that it makes a lot of sense to special-case brackets as delimiting non-trailer runs. (for other readers) This support for non-trailer lines grew out of Linux Kernel practices. At least according to this thread: https://lore.kernel.org/git/CA+55aFzN4SnenchxPScn61_apzitGAPtoYEd49iLZPxgK0KQGw@mail.gmail.com/ (See also in particular: https://lore.kernel.org/git/20150905000745.GC11443@sigill.intra.peff.net/ ) And part of the back-and-forth in that thread is an inherent tension: the trailer format is loose. All you need is a some alphanumerics/hyphens and a colon. So it is simple to accidentally slip in a *real* trailer line along with all the cruft. Like Peff’s example shows: > > Signed-off-by: whomever > [peff: there's a really interesting thing going on > here: the comment is free-form text that happens to > use a colon in a sentence, but we'll interpret it > as a trailer with key "here"] > Signed-off-by: another unlucky soul Imagine you had internalized the trailer parsing rules (which you shouldn’t have to but anyway); it would still be easy to accidentally write something like the above. But with an additional `[]` rule you don’t have to worry: • A run of non-trailer lines starts with regex `^[` • And ends 0 or more lines later with regex `]$` • In addition to the existing rules And `[]` are illegal in trailer keys anyway. This is a very Linux (and Git project) specific additional rule, but the non-trailer lines rules were always like that. > > That said, I think there are cases without brackets that are also > confusing. Like: > > Let me finish this commit message by telling you all about this > amazing url: > > https://example.com Yeah exactly. >[snip] >> diff --git a/trailer.c b/trailer.c >> index 6d8ec7fa8d8..971ae459596 100644 >> --- a/trailer.c >> +++ b/trailer.c >> @@ -635,8 +635,13 @@ static ssize_t find_separator(const char *line, const char *separators) >> int whitespace_found = 0; >> const char *c; >> for (c = line; *c; c++) { >> - if (strchr(separators, *c)) >> + if (strchr(separators, *c)) { >> + /* avoid accidental URL matches (://) */ >> + if (*c == ':' && c[1] == '/' && c[2] == '/' && >> + !whitespace_found) >> + return -1; >> return c - line; >> + } > > As discussed elsewhere, we are free to match with short-circuiting > because of the NUL termination. But that also means we could write this > as: > > if (starts_with(c, "://") && !whitespace_found) > > which is perhaps a little more readable. Oh for sure, much more readable. Thanks! ^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2026-08-06 20:18 UTC | newest] Thread overview: 11+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-06-04 21:27 trailers: --only-trailers normalizes URLs to trailers Kristoffer Haugsbakk 2026-06-09 0:43 ` Jeff King 2026-06-10 14:21 ` Kristoffer Haugsbakk 2026-06-11 6:56 ` Jeff King 2026-06-11 7:03 ` Kristoffer Haugsbakk 2026-08-02 19:57 ` [PATCH] trailers: stop recognizing URLs as trailers kristofferhaugsbakk 2026-08-02 22:36 ` Junio C Hamano 2026-08-03 12:11 ` Kristoffer Haugsbakk 2026-08-03 15:20 ` Jeff King 2026-08-03 15:39 ` Junio C Hamano 2026-08-06 20:17 ` Kristoffer Haugsbakk
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox