Expose gpgsig in pretty-print
cover Expose gpgsig in pretty-print
Currently, users who do not have GPG installed have no way to discern signed from unsigned commits without examining raw commit data. I propose two new pretty-print placeholders to expose this information:
%GR: full ("R"aw) contents of gpgsig header %G+: Y/N if the commit has nonempty gpgsig header or not
The second is of course much more likely to be used, but having exposed the one, exposing the other too adds almost no complexity.
I'm open to suggestion on the names of these placeholders.
This commit is based on master but e5a329a279 ("run-command: report exec failure" 2018-12-11) is required for the tests to pass.
One note is that this change touches areas of the pretty-format documentation that are radically revamped in aw/pretty-trailers: see 42617752d4 ("doc: group pretty-format.txt placeholders descriptions" 2018-12-08). I have another version of this branch based on that branch as well, so you can use that in case conflicts with aw/pretty-trailers arise.
See:
- https://github.com/jpassaro/git/tree/jp/pretty-expose-gpgsig
- https://github.com/jpassaro/git/tree/jp/pretty-expose-gpgsig--based-on-aw-pretty-trailers
John Passaro (4):
pretty: expose raw commit signature t/t7510-signed-commit.sh: test new placeholders doc, tests: pretty behavior when gpg missing docs/pretty-formats: add explanation + copy edits
Documentation/pretty-formats.txt | 21 ++++-- pretty.c | 36 ++++++++- t/t7510-signed-commit.sh | 125 +++++++++++++++++++++++++++++-- 3 files changed, 167 insertions(+), 15 deletions(-)
base-commit: 5d826e972970a784bd7a7bdf587512510097b8c7
prerequisite-patch-id: aedfe228fd293714d9cd0392ac22ff1cba7365db
Signature · 1 line
2.19.1
PATCH 1/4 pretty: expose raw commit signature
Add new pretty-format placeholders %GR and %G+ to support inspecting gpgsig commit header in pretty format, even if GPG is not available.
--- Documentation/pretty-formats.txt | 2 ++ pretty.c | 36 ++++++++++++++++++++++++++++++-- 2 files changed, 36 insertions(+), 2 deletions(-)
Documentation/pretty-formats.txt +2 -0
@@ -142,6 +142,8 @@ The placeholders are: ifndef::git-rev-list[] - '%N': commit notes endif::git-rev-list[] +- '%GR': contents of the commits signature (blank when unsigned) +- '%G+': "Y" if the commit is signed, "N" otherwise - '%GG': raw verification message from GPG for a signed commit - '%G?': show "G" for a good (valid) signature, "B" for a bad signature,
pretty.c +34 -2
@@ -768,6 +768,9 @@ struct format_commit_context { unsigned commit_header_parsed:1; unsigned commit_message_parsed:1;struct signature_check signature_check; + unsigned signature_checked:2; +struct strbuf signature; +struct strbuf signature_payload;enum flush_type flush_type;enum trunc_type truncate;const char *message;
@@ -1228,8 +1231,30 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */ }if (placeholder[0 ] =='G' ) { -if (!c->signature_check.result) -check_commit_signature (c->commit, &(c->signature_check)); +if (!c->signature_checked) { +parse_signed_commit (c->commit, &(c->signature_payload), &(c->signature)); + c->signature_checked =1 ; + } +switch (placeholder[1 ]) { +case 'R' : +strbuf_addbuf (sb, &(c->signature)); +break ; +case '+' : +strbuf_addch (sb, c->signature.len ?'Y' :'N' ); +break ; +default : + goto do_signature_check; + } +return 2 ; + +do_signature_check: +if (c->signature_checked <2 ) { +if (c->signature.len) +check_signature (c->signature_payload.buf, c->signature_payload.len, + c->signature.buf, c->signature.len, + &(c->signature_check)); + c->signature_checked =2 ; + }switch (placeholder[1 ]) {case 'G' :if (c->signature_check.gpg_output)
@@ -1246,6 +1271,9 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */case 'Y' :case 'R' :strbuf_addch (sb, c->signature_check.result); +break ; +case 0 :// i.e. no signature so we never ran the check +strbuf_addch (sb,'N' ); }break ;case 'S' :
@@ -1527,6 +1555,8 @@ void format_commit_message(const struct commit *commit, context.commit = commit; context.pretty_ctx = pretty_ctx; context.wrap_start = sb->len; +strbuf_init (&context.signature,0 ); +strbuf_init (&context.signature_payload,0 );/* * convert a commit message to UTF-8 first * as far as 'format_commit_item' assumes it in UTF-8
@@ -1556,6 +1586,8 @@ void format_commit_message(const struct commit *commit,strbuf_attach (sb, out, outsz, outsz +1 ); } +strbuf_release (&context.signature); +strbuf_release (&context.signature_payload);free (context.commit_encoding);unuse_commit_buffer (commit, context.message); }
Signature · 1 line
2.19.1
PATCH 2/4 t/t7510-signed-commit.sh: test new placeholders
In reply to John PassaroTest that %GR output ("Raw" contents of "gpgsig" header) looks like ASCII-armored GPG signature.
Test %G+ (Y/N for presence/absence of "gpgsig" header) by adding it to existing format tests for signed commits.
--- t/t7510-signed-commit.sh | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-)
t/t7510-signed-commit.sh +25 -5
@@ -177,8 +177,9 @@ test_expect_success GPG 'show good signature with custom format' ' C O Mitter <[email protected]> 73D758744BE721698EC54E8713B6F51ECDDE430D 73D758744BE721698EC54E8713B6F51ECDDE430D + Y EOF - git log -1 --format="%G?%n%GK%n%GS%n%GF%n%GP" sixth-signed >actual && + git log -1 --format="%G?%n%GK%n%GS%n%GF%n%GP%n%G+" sixth-signed >actual && test_cmp expect actual '
@@ -189,8 +190,9 @@ test_expect_success GPG 'show bad signature with custom format' ' C O Mitter <[email protected]> + Y EOF - git log -1 --format="%G?%n%GK%n%GS%n%GF%n%GP" $(cat forged1.commit) >actual && + git log -1 --format="%G?%n%GK%n%GS%n%GF%n%GP%n%G+" $(cat forged1.commit) >actual && test_cmp expect actual '
@@ -201,8 +203,9 @@ test_expect_success GPG 'show untrusted signature with custom format' ' Eris Discordia <[email protected]> F8364A59E07FFE9F4D63005A65A0EEA02E30CAD7 D4BE22311AD3131E5EDA29A461092E85B7227189 + Y EOF - git log -1 --format="%G?%n%GK%n%GS%n%GF%n%GP" eighth-signed-alt >actual && + git log -1 --format="%G?%n%GK%n%GS%n%GF%n%GP%n%G+" eighth-signed-alt >actual && test_cmp expect actual '
@@ -213,8 +216,9 @@ test_expect_success GPG 'show unknown signature with custom format' ' + Y EOF - GNUPGHOME="$GNUPGHOME_NOT_USED" git log -1 --format="%G?%n%GK%n%GS%n%GF%n%GP" eighth-signed-alt >actual && + GNUPGHOME="$GNUPGHOME_NOT_USED" git log -1 --format="%G?%n%GK%n%GS%n%GF%n%GP%n%G+" eighth-signed-alt >actual && test_cmp expect actual '
@@ -225,11 +229,27 @@ test_expect_success GPG 'show lack of signature with custom format' ' + N EOF - git log -1 --format="%G?%n%GK%n%GS%n%GF%n%GP" seventh-unsigned >actual && + git log -1 --format="%G?%n%GK%n%GS%n%GF%n%GP%n%G+" seventh-unsigned >actual && test_cmp expect actual ' +test_expect_success GPG 'show lack of raw signature with custom format' ' + git log -1 --format=format:"%GR" seventh-unsigned > actual && + test_must_be_empty actual +' + +test_expect_success GPG 'show raw signature with custom format' ' + git log -1 --format=format:"%GR" sixth-signed >output && + cat output && + head -n1 output | grep -q "^---*BEGIN PGP SIGNATURE---*$" && + sed 1d output | grep -q "^$" && + sed "1,/^$/d" output | grep -q "^[a-zA-Z0-9+/][a-zA-Z0-9+/=]*$" && + tail -n2 output | head -n1 | grep -q "^=[a-zA-Z0-9+/][a-zA-Z0-9+/=]*$" && + tail -n1 output | grep -q "^---*END PGP SIGNATURE---*$" +' + test_expect_success GPG 'log.showsignature behaves like --show-signature' ' test_config log.showsignature true && git show initial >actual &&
Signature · 1 line
2.19.1
PATCH 3/4 doc, tests: pretty behavior when gpg missing
In reply to John PassaroTest that when GPG cannot be run, new placeholders %GR and %G+ are unaffected, %G? always returns 'N', and other GPG-related placeholders return blank.
As of e5a329a279 ("run-command: report exec failure" 2018-12-11), if GPG cannot be run and placeholders requiring GPG are given, git complains to stderr that GPG cannot be found. That commit included low-level tests for this behavior. Now, test it also at the level of everyday user commands.
--- Documentation/pretty-formats.txt | 6 +- t/t7510-signed-commit.sh | 95 ++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+), 2 deletions(-)
Documentation/pretty-formats.txt +4 -2
@@ -144,7 +144,9 @@ ifndef::git-rev-list[] endif::git-rev-list[] - '%GR': contents of the commits signature (blank when unsigned) - '%G+': "Y" if the commit is signed, "N" otherwise -- '%GG': raw verification message from GPG for a signed commit +- '%GG': raw verification message from GPG for a signed commit. + This and all the other %G* placeholders, other than %GR, %G+, and + %G?, return blank if GPG cannot be run. - '%G?': show "G" for a good (valid) signature, "B" for a bad signature, "U" for a good signature with unknown validity,
@@ -152,7 +154,7 @@ endif::git-rev-list[] "Y" for a good signature made by an expired key, "R" for a good signature made by a revoked key, "E" if the signature cannot be checked (e.g. missing key) - and "N" for no signature + and "N" for no signature (e.g. unsigned, or GPG cannot be run) - '%GS': show the name of the signer for a signed commit - '%GK': show the key used to sign a signed commit - '%GF': show the fingerprint of the key used to sign a signed commit
t/t7510-signed-commit.sh +95 -0
113 lines not on this page · raw message
Signature · 1 line
2.19.1
PATCH 4/4 docs/pretty-formats: add explanation + copy edits
In reply to John PassaroClarify description of %G? = "U" to say it can mean good signature but untrusted key.
Make wording consistent between %G* placeholders and other placeholders by removing the verb "show".
--- Documentation/pretty-formats.txt | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-)
Documentation/pretty-formats.txt +7 -6
@@ -147,18 +147,19 @@ endif::git-rev-list[] - '%GG': raw verification message from GPG for a signed commit. This and all the other %G* placeholders, other than %GR, %G+, and %G?, return blank if GPG cannot be run. -- '%G?': show "G" for a good (valid) signature, +- '%G?': "G" for a good (valid) signature, "B" for a bad signature, - "U" for a good signature with unknown validity, + "U" for a good signature with unknown validity (e.g. key is known but + not trusted), "X" for a good signature that has expired, "Y" for a good signature made by an expired key, "R" for a good signature made by a revoked key, "E" if the signature cannot be checked (e.g. missing key) and "N" for no signature (e.g. unsigned, or GPG cannot be run) -- '%GS': show the name of the signer for a signed commit -- '%GK': show the key used to sign a signed commit -- '%GF': show the fingerprint of the key used to sign a signed commit -- '%GP': show the fingerprint of the primary key whose subkey was used +- '%GS': name of the signer for a signed commit +- '%GK': key used to sign a signed commit +- '%GF': fingerprint of the key used to sign a signed commit +- '%GP': fingerprint of the primary key whose subkey was used to sign a signed commit - '%gD': reflog selector, e.g., `refs/stash@{1}` or `refs/stash@{2 minutes ago`}; the format follows the rules described
Signature · 1 line
2.19.1
Quoted 32 lines · John Passaro
Currently, users who do not have GPG installed have no way to discern signed from unsigned commits without examining raw commit data. I propose two new pretty-print placeholders to expose this information:
%GR: full ("R"aw) contents of gpgsig header %G+: Y/N if the commit has nonempty gpgsig header or not
The second is of course much more likely to be used, but having exposed the one, exposing the other too adds almost no complexity.
I'm open to suggestion on the names of these placeholders.
This commit is based on master but
e5a329a279("run-command: report exec failure" 2018-12-11) is required for the tests to pass.One note is that this change touches areas of the pretty-format documentation that are radically revamped in aw/pretty-trailers: see
42617752d4("doc: group pretty-format.txt placeholders descriptions" 2018-12-08). I have another version of this branch based on that branch as well, so you can use that in case conflicts with aw/pretty-trailers arise.See:
- https://github.com/jpassaro/git/tree/jp/pretty-expose-gpgsig
- https://github.com/jpassaro/git/tree/jp/pretty-expose-gpgsig--based-on-aw-pretty-trailersJohn Passaro (4):
pretty: expose raw commit signaturet/t7510-signed-commit.sh: test new placeholders doc, tests: pretty behavior when gpg missing docs/pretty-formats: add explanation + copy edits
Quoted 8 lines
Documentation/pretty-formats.txt | 21 ++++-- pretty.c | 36 ++++++++- t/t7510-signed-commit.sh | 125 +++++++++++++++++++++++++++++-- 3 files changed, 167 insertions(+), 15 deletions(-)base-commit:
5d826e972970a784bd7a7bdf587512510097b8c7
prerequisite-patch-id:aedfe228fd293714d9cd0392ac22ff1cba7365db
Just a suggestion: since the raw signature is not very useful without the commit data to check it against, and the commit data is non-trivial to construct (requires mangling raw data anyway), maybe you could either add another placeholder to get the data for signature verification, or (alternatively or simultaneously) add a placeholder that prints both data and signature in the OpenPGP message format (i.e. something you can pass straight to 'gpg --verify').
Signature · 2 lines
Best regards, Michał Górny
Quoted 43 lines · Michał Górny
Quoted 32 lines · John Passaro
Currently, users who do not have GPG installed have no way to discern signed from unsigned commits without examining raw commit data. I propose two new pretty-print placeholders to expose this information:
%GR: full ("R"aw) contents of gpgsig header %G+: Y/N if the commit has nonempty gpgsig header or not
The second is of course much more likely to be used, but having exposed the one, exposing the other too adds almost no complexity.
I'm open to suggestion on the names of these placeholders.
This commit is based on master but
e5a329a279("run-command: report exec failure" 2018-12-11) is required for the tests to pass.One note is that this change touches areas of the pretty-format documentation that are radically revamped in aw/pretty-trailers: see
42617752d4("doc: group pretty-format.txt placeholders descriptions" 2018-12-08). I have another version of this branch based on that branch as well, so you can use that in case conflicts with aw/pretty-trailers arise.See:
- https://github.com/jpassaro/git/tree/jp/pretty-expose-gpgsig
- https://github.com/jpassaro/git/tree/jp/pretty-expose-gpgsig--based-on-aw-pretty-trailersJohn Passaro (4):
pretty: expose raw commit signaturet/t7510-signed-commit.sh: test new placeholders doc, tests: pretty behavior when gpg missing docs/pretty-formats: add explanation + copy editsQuoted 8 lines
Documentation/pretty-formats.txt | 21 ++++-- pretty.c | 36 ++++++++- t/t7510-signed-commit.sh | 125 +++++++++++++++++++++++++++++-- 3 files changed, 167 insertions(+), 15 deletions(-)base-commit:
5d826e972970a784bd7a7bdf587512510097b8c7
prerequisite-patch-id:aedfe228fd293714d9cd0392ac22ff1cba7365db
Quoted 8 lines
Just a suggestion: since the raw signature is not very useful without the commit data to check it against, and the commit data is non-trivial to construct (requires mangling raw data anyway), maybe you could either add another placeholder to get the data for signature verification, or (alternatively or simultaneously) add a placeholder that prints both data and signature in the OpenPGP message format (i.e. something you can pass straight to 'gpg --verify').
That's a great idea!
Then I might rename the other new placeholders too:
%Gs: signed commit signature (blank when unsigned)
%Gp: signed commit payload (i.e. in practice minus the gpgsig header; also blank when unsigned as well)
%Gq: query/question whether is signed commit ("Y"/"N")
Thus establishing %G<lowercase> as the gpg-related placeholders that do not actually require gpg.
And add a test that %Gp%n%Gs or the like passes gpg --verify.
I'll put in a v2 later today or tomorrow. Thank you for the feedback!
--
JP
Quoted 62 lines · John Passaro
Quoted 43 lines · Michał Górny
Quoted 32 lines · John Passaro
Currently, users who do not have GPG installed have no way to discern signed from unsigned commits without examining raw commit data. I propose two new pretty-print placeholders to expose this information:
%GR: full ("R"aw) contents of gpgsig header %G+: Y/N if the commit has nonempty gpgsig header or not
The second is of course much more likely to be used, but having exposed the one, exposing the other too adds almost no complexity.
I'm open to suggestion on the names of these placeholders.
This commit is based on master but
e5a329a279("run-command: report exec failure" 2018-12-11) is required for the tests to pass.One note is that this change touches areas of the pretty-format documentation that are radically revamped in aw/pretty-trailers: see
42617752d4("doc: group pretty-format.txt placeholders descriptions" 2018-12-08). I have another version of this branch based on that branch as well, so you can use that in case conflicts with aw/pretty-trailers arise.See:
- https://github.com/jpassaro/git/tree/jp/pretty-expose-gpgsig
- https://github.com/jpassaro/git/tree/jp/pretty-expose-gpgsig--based-on-aw-pretty-trailersJohn Passaro (4):
pretty: expose raw commit signaturet/t7510-signed-commit.sh: test new placeholders doc, tests: pretty behavior when gpg missing docs/pretty-formats: add explanation + copy editsQuoted 8 lines
Documentation/pretty-formats.txt | 21 ++++-- pretty.c | 36 ++++++++- t/t7510-signed-commit.sh | 125 +++++++++++++++++++++++++++++-- 3 files changed, 167 insertions(+), 15 deletions(-)base-commit:
5d826e972970a784bd7a7bdf587512510097b8c7
prerequisite-patch-id:aedfe228fd293714d9cd0392ac22ff1cba7365dbQuoted 8 lines
Just a suggestion: since the raw signature is not very useful without the commit data to check it against, and the commit data is non-trivial to construct (requires mangling raw data anyway), maybe you could either add another placeholder to get the data for signature verification, or (alternatively or simultaneously) add a placeholder that prints both data and signature in the OpenPGP message format (i.e. something you can pass straight to 'gpg --verify').
That's a great idea!
Then I might rename the other new placeholders too:
%Gs: signed commit signature (blank when unsigned)
%Gp: signed commit payload (i.e. in practice minus the gpgsig header; also blank when unsigned as well)
%Gq: query/question whether is signed commit ("Y"/"N")
Quoted 7 lines
Thus establishing %G<lowercase> as the gpg-related placeholders that do not actually require gpg.
And add a test that %Gp%n%Gs or the like passes gpg --verify.
I'll put in a v2 later today or tomorrow. Thank you for the feedback!
Technically speaking, '%Gp%n%Gs' sounds a bit odd, given that the payload needs to be preceded by the PGP message header but instead of footer it has the signature's header. Also note that some lines in the payload may need to be escaped.
Signature · 2 lines
Best regards, Michał Górny
Quoted 69 lines · Michał Górny
Quoted 67 lines · John Passaro
Quoted 43 lines · Michał Górny
Quoted 32 lines · John Passaro
Currently, users who do not have GPG installed have no way to discern signed from unsigned commits without examining raw commit data. I propose two new pretty-print placeholders to expose this information:
%GR: full ("R"aw) contents of gpgsig header %G+: Y/N if the commit has nonempty gpgsig header or not
The second is of course much more likely to be used, but having exposed the one, exposing the other too adds almost no complexity.
I'm open to suggestion on the names of these placeholders.
This commit is based on master but
e5a329a279("run-command: report exec failure" 2018-12-11) is required for the tests to pass.One note is that this change touches areas of the pretty-format documentation that are radically revamped in aw/pretty-trailers: see
42617752d4("doc: group pretty-format.txt placeholders descriptions" 2018-12-08). I have another version of this branch based on that branch as well, so you can use that in case conflicts with aw/pretty-trailers arise.See:
- https://github.com/jpassaro/git/tree/jp/pretty-expose-gpgsig
- https://github.com/jpassaro/git/tree/jp/pretty-expose-gpgsig--based-on-aw-pretty-trailersJohn Passaro (4):
pretty: expose raw commit signaturet/t7510-signed-commit.sh: test new placeholders doc, tests: pretty behavior when gpg missing docs/pretty-formats: add explanation + copy editsQuoted 8 lines
Documentation/pretty-formats.txt | 21 ++++-- pretty.c | 36 ++++++++- t/t7510-signed-commit.sh | 125 +++++++++++++++++++++++++++++-- 3 files changed, 167 insertions(+), 15 deletions(-)base-commit:
5d826e972970a784bd7a7bdf587512510097b8c7
prerequisite-patch-id:aedfe228fd293714d9cd0392ac22ff1cba7365dbQuoted 8 lines
Just a suggestion: since the raw signature is not very useful without the commit data to check it against, and the commit data is non-trivial to construct (requires mangling raw data anyway), maybe you could either add another placeholder to get the data for signature verification, or (alternatively or simultaneously) add a placeholder that prints both data and signature in the OpenPGP message format (i.e. something you can pass straight to 'gpg --verify').
That's a great idea!
Then I might rename the other new placeholders too:
%Gs: signed commit signature (blank when unsigned)
%Gp: signed commit payload (i.e. in practice minus the gpgsig header; also blank when unsigned as well)
%Gq: query/question whether is signed commit ("Y"/"N")Thus establishing %G<lowercase> as the gpg-related placeholders that do not actually require gpg.
And add a test that %Gp%n%Gs or the like passes gpg --verify.
Quoted 7 lines
Quoted 2 lines
I'll put in a v2 later today or tomorrow. Thank you for the feedback!
Technically speaking, '%Gp%n%Gs' sounds a bit odd, given that the payload needs to be preceded by the PGP message header but instead of footer it has the signature's header. Also note that some lines in the payload may need to be escaped.
It's indeed failing with
"-----BEGIN PGP SIGNED MESSAGE-----%n%Gp%n%Gs"
This appears to be a misunderstanding on my part of how cleartext GPG messages work, as this message seems to fail verification even when I construct it manually:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256
tree 3820419b50e9827493beedf6a1423e7d9c7edf3b parent 356f37356edf1a45c8494870e1c051e2fbe529fa author A U Thor <[email protected]> 1112912413 -0700 committer C O Mitter <[email protected]> 1112912533 -0700
sixth
-----BEGIN PGP SIGNATURE-----
iHQEABECADQWIQRz11h0S+chaY7FTocTtvUezd5DDQUCXBQzKRYcY29tbWl0dGVy QGV4YW1wbGUuY29tAAoJEBO29R7N3kMN2QYAnA2A/VpD4qMI9rJlIYnyyO32rTXz AJ0drWlJsASMcf6AEX6nSQPxWq81Fg==
=fr2F
-----END PGP SIGNATURE-----
I got this by running tho following inside the trash directory for t7510, which as far as I can tell is roughly equivalent to
The gpg --verify fails.
{
echo "-----BEGIN PGP SIGNED MESSAGE-----"
echo Hash: SHA256
echo
git cat-file commit sixth-signed | perl -ne '/^(?:gpgsig)? / || print' git cat-file commit sixth-signed | perl -ne 's/^(?:gpgsig)? // && print'
} | tee commit-as-signed-message | gpg --verify
All seems to work fine when I treat %Gs as a detached signature. How should the combined message be constructed properly? (Goes to usefulness of printing signature payload, and indeed of raw crypto data in general.)
Quoted 3 lines
--
Best regards,
Michał Górny
Quoted 103 lines · John Passaro
Quoted 69 lines · Michał Górny
Quoted 67 lines · John Passaro
Quoted 43 lines · Michał Górny
Quoted 32 lines · John Passaro
Currently, users who do not have GPG installed have no way to discern signed from unsigned commits without examining raw commit data. I propose two new pretty-print placeholders to expose this information:
%GR: full ("R"aw) contents of gpgsig header %G+: Y/N if the commit has nonempty gpgsig header or not
The second is of course much more likely to be used, but having exposed the one, exposing the other too adds almost no complexity.
I'm open to suggestion on the names of these placeholders.
This commit is based on master but
e5a329a279("run-command: report exec failure" 2018-12-11) is required for the tests to pass.One note is that this change touches areas of the pretty-format documentation that are radically revamped in aw/pretty-trailers: see
42617752d4("doc: group pretty-format.txt placeholders descriptions" 2018-12-08). I have another version of this branch based on that branch as well, so you can use that in case conflicts with aw/pretty-trailers arise.See:
- https://github.com/jpassaro/git/tree/jp/pretty-expose-gpgsig
- https://github.com/jpassaro/git/tree/jp/pretty-expose-gpgsig--based-on-aw-pretty-trailersJohn Passaro (4):
pretty: expose raw commit signaturet/t7510-signed-commit.sh: test new placeholders doc, tests: pretty behavior when gpg missing docs/pretty-formats: add explanation + copy editsQuoted 8 lines
Documentation/pretty-formats.txt | 21 ++++-- pretty.c | 36 ++++++++- t/t7510-signed-commit.sh | 125 +++++++++++++++++++++++++++++-- 3 files changed, 167 insertions(+), 15 deletions(-)base-commit:
5d826e972970a784bd7a7bdf587512510097b8c7
prerequisite-patch-id:aedfe228fd293714d9cd0392ac22ff1cba7365dbQuoted 8 lines
Just a suggestion: since the raw signature is not very useful without the commit data to check it against, and the commit data is non-trivial to construct (requires mangling raw data anyway), maybe you could either add another placeholder to get the data for signature verification, or (alternatively or simultaneously) add a placeholder that prints both data and signature in the OpenPGP message format (i.e. something you can pass straight to 'gpg --verify').
That's a great idea!
Then I might rename the other new placeholders too:
%Gs: signed commit signature (blank when unsigned)
%Gp: signed commit payload (i.e. in practice minus the gpgsig header; also blank when unsigned as well)
%Gq: query/question whether is signed commit ("Y"/"N")Thus establishing %G<lowercase> as the gpg-related placeholders that do not actually require gpg.
And add a test that %Gp%n%Gs or the like passes gpg --verify.
Quoted 7 lines
Quoted 2 lines
I'll put in a v2 later today or tomorrow. Thank you for the feedback!
Technically speaking, '%Gp%n%Gs' sounds a bit odd, given that the payload needs to be preceded by the PGP message header but instead of footer it has the signature's header. Also note that some lines in the payload may need to be escaped.
It's indeed failing with
"-----BEGIN PGP SIGNED MESSAGE-----%n%Gp%n%Gs"This appears to be a misunderstanding on my part of how cleartext GPG messages work, as this message seems to fail verification even when I construct it manually:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256tree
3820419b50e9827493beedf6a1423e7d9c7edf3bparent356f37356edf1a45c8494870e1c051e2fbe529faauthor A U Thor <[email protected]> 1112912413 -0700 committer C O Mitter <[email protected]> 1112912533 -0700sixth
-----BEGIN PGP SIGNATURE-----iHQEABECADQWIQRz11h0S+chaY7FTocTtvUezd5DDQUCXBQzKRYcY29tbWl0dGVy QGV4YW1wbGUuY29tAAoJEBO29R7N3kMN2QYAnA2A/VpD4qMI9rJlIYnyyO32rTXz AJ0drWlJsASMcf6AEX6nSQPxWq81Fg==
=fr2F
-----END PGP SIGNATURE-----
Quoted 10 lines
I got this by running tho following inside the trash directory for t7510, which as far as I can tell is roughly equivalent to
The gpg --verify fails.
{
echo "-----BEGIN PGP SIGNED MESSAGE-----"
echo Hash: SHA256
echo
git cat-file commit sixth-signed | perl -ne '/^(?:gpgsig)? / || print' git cat-file commit sixth-signed | perl -ne 's/^(?:gpgsig)? // && print'
} | tee commit-as-signed-message | gpg --verify
I should add that when I took out Hash: SHA256 (don't ask), gpg went from saying "signature digest conflict" to saying "BAD signature". Not quite as bad but still confusing.
Quoted 10 lines
All seems to work fine when I treat %Gs as a detached signature. How should the combined message be constructed properly? (Goes to usefulness of printing signature payload, and indeed of raw crypto data in general.)
Quoted 3 lines
--
Best regards,
Michał Górny
Quoted 5 lines · John Passaro
Then I might rename the other new placeholders too:
%Gs: signed commit signature (blank when unsigned)
%Gp: signed commit payload (i.e. in practice minus the gpgsig header; also blank when unsigned as well)
One complication: the pretty-printing code sees the commit data in the i18n.logOutputEncoding charset (utf8 by default). But the signature will be over the raw commit data. That's also utf8 by default, but there may be an encoding header indicating that it's something else. In that case, you couldn't actually verify the signature from the "%Gs%Gp" pair.
I don't think that's insurmountable in the code. You'll have to jump through a few hoops to make sure you have the _original_ payload, but we obviously do have that data. However, it does feel a little weird to include content from a different encoding in the middle of the log output stream which claims to be i18n.logOutputEncoding.
-Peff
Quoted 1 line · John Passaro
All seems to work fine when I treat %Gs as a detached signature.
In light of this, my best guess as to why the cleartext PGP message didn't verify properly is that the commit data normally doesn't end with \n, but as far as I can tell there's no way to express that in the cleartext format. I don't see a way around this. However, as long as the following works, I think we have proof-of-concept that this enhancement allows you to play with signature data however you please without leaving it to git under the hood:
gpg --verify <(git show -s --format=format:%Gs commit) <(git show -s --format=format:%Gp commit)
Quoted 15 lines · Jeff King
Quoted 5 lines · John Passaro
Then I might rename the other new placeholders too:
%Gs: signed commit signature (blank when unsigned)
%Gp: signed commit payload (i.e. in practice minus the gpgsig header; also blank when unsigned as well)One complication: the pretty-printing code sees the commit data in the i18n.logOutputEncoding charset (utf8 by default). But the signature will be over the raw commit data. That's also utf8 by default, but there may be an encoding header indicating that it's something else. In that case, you couldn't actually verify the signature from the "%Gs%Gp" pair.
Quoted 6 lines
I don't think that's insurmountable in the code. You'll have to jump through a few hoops to make sure you have the _original_ payload, but we obviously do have that data. However, it does feel a little weird to include content from a different encoding in the middle of the log output stream which claims to be i18n.logOutputEncoding.
Thanks for the feedback! This is an interesting conflict. If the user requests %Gp, the payload for the signature, they almost certainly do want it in the original encoding; if i18n.logOutputEncoding is something incompatible, whether explicitly or by default, that seems like an error. Not much we can do to reconcile the two requests (commit encoding vs output encoding) so seems reasonable to treat it as fatal.
Updated patch coming as soon as I work out Peff's aforementioned "few hoops" to get properly encoded data -- and also how to test success and failure!
Quoted 7 lines · John Passaro
Quoted 1 line · John Passaro
All seems to work fine when I treat %Gs as a detached signature.
In light of this, my best guess as to why the cleartext PGP message didn't verify properly is that the commit data normally doesn't end with \n, but as far as I can tell there's no way to express that in the cleartext format. I don't see a way around this.
You are most likely right. I've just skimmed through RFC 4880 and indeed it seems to rely on the newline encoding being quite normalized in the message.
Quoted 7 lines
However, as long
as the following works, I think we have proof-of-concept that this enhancement allows you to play with signature data however you please without leaving it to git under the hood:gpg --verify <(git show -s --format=format:%Gs commit) <(git show -s --format=format:%Gp commit)
That's a nice trick. Thanks for the effort you're putting into this!
Quoted 35 lines · Jeff King
Quoted 15 lines · John Passaro
Quoted 6 lines
Then I might rename the other new placeholders too:
%Gs: signed commit signature (blank when unsigned)
%Gp: signed commit payload (i.e. in practice minus the gpgsig header; also blank when unsigned as well)One complication: the pretty-printing code sees the commit data in the i18n.logOutputEncoding charset (utf8 by default). But the signature will be over the raw commit data. That's also utf8 by default, but there may be an encoding header indicating that it's something else. In that case, you couldn't actually verify the signature from the "%Gs%Gp" pair.
Quoted 6 lines
I don't think that's insurmountable in the code. You'll have to jump through a few hoops to make sure you have the _original_ payload, but we obviously do have that data. However, it does feel a little weird to include content from a different encoding in the middle of the log output stream which claims to be i18n.logOutputEncoding.
Thanks for the feedback! This is an interesting conflict. If the user requests %Gp, the payload for the signature, they almost certainly do want it in the original encoding; if i18n.logOutputEncoding is something incompatible, whether explicitly or by default, that seems like an error. Not much we can do to reconcile the two requests (commit encoding vs output encoding) so seems reasonable to treat it as fatal.
Updated patch coming as soon as I work out Peff's aforementioned "few hoops" to get properly encoded data -- and also how to test success and failure!
Signature · 2 lines
Best regards, Michał Górny
Quoted 7 lines · Michał Górny
Just a suggestion: since the raw signature is not very useful without the commit data to check it against, and the commit data is non-trivial to construct (requires mangling raw data anyway), maybe you could either add another placeholder to get the data for signature verification, or (alternatively or simultaneously) add a placeholder that prints both data and signature in the OpenPGP message format (i.e. something you can pass straight to 'gpg --verify').
Yeah, the last would be the most usable; anything short of that, I have to suspect that going from "cat-file commit", rather than using this new %Gsomething placeholder, would be more practical.