From ffb6d7d5c99e4097e512def20b0133b7ee900953 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20G=C3=B6tte?= Date: Sun, 31 Mar 2013 18:00:14 +0200 Subject: [PATCH 1/5] Move commit GPG signature verification to commit.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Sebastian Götte Signed-off-by: Junio C Hamano --- commit.c | 59 ++++++++++++++++++++++++++++++++ commit.h | 10 ++++++ gpg-interface.h | 11 ++++++ pretty.c | 91 +++++++------------------------------------------ 4 files changed, 93 insertions(+), 78 deletions(-) diff --git a/commit.c b/commit.c index b4512ab0b2e..66a3f4e8f42 100644 --- a/commit.c +++ b/commit.c @@ -1041,6 +1041,65 @@ free_return: free(buf); } +static struct { + char result; + const char *check; +} sigcheck_gpg_status[] = { + { 'G', "\n[GNUPG:] GOODSIG " }, + { 'B', "\n[GNUPG:] BADSIG " }, +}; + +static void parse_gpg_output(struct signature_check *sigc) +{ + const char *buf = sigc->gpg_status; + int i; + + for (i = 0; i < ARRAY_SIZE(sigcheck_gpg_status); i++) { + const char *found = strstr(buf, sigcheck_gpg_status[i].check); + const char *next; + if (!found) + continue; + sigc->result = sigcheck_gpg_status[i].result; + found += strlen(sigcheck_gpg_status[i].check); + sigc->key = xmemdupz(found, 16); + found += 17; + next = strchrnul(found, '\n'); + sigc->signer = xmemdupz(found, next - found); + break; + } +} + +void check_commit_signature(const struct commit* commit, struct signature_check *sigc) +{ + struct strbuf payload = STRBUF_INIT; + struct strbuf signature = STRBUF_INIT; + struct strbuf gpg_output = STRBUF_INIT; + struct strbuf gpg_status = STRBUF_INIT; + int status; + + sigc->result = 'N'; + + if (parse_signed_commit(commit->object.sha1, + &payload, &signature) <= 0) + goto out; + status = verify_signed_buffer(payload.buf, payload.len, + signature.buf, signature.len, + &gpg_output, &gpg_status); + if (status && !gpg_output.len) + goto out; + sigc->gpg_output = strbuf_detach(&gpg_output, NULL); + sigc->gpg_status = strbuf_detach(&gpg_status, NULL); + parse_gpg_output(sigc); + + out: + strbuf_release(&gpg_status); + strbuf_release(&gpg_output); + strbuf_release(&payload); + strbuf_release(&signature); +} + + + void append_merge_tag_headers(struct commit_list *parents, struct commit_extra_header ***tail) { diff --git a/commit.h b/commit.h index 2d90d9c27c8..c24b844ad64 100644 --- a/commit.h +++ b/commit.h @@ -5,6 +5,7 @@ #include "tree.h" #include "strbuf.h" #include "decorate.h" +#include "gpg-interface.h" struct commit_list { struct commit *item; @@ -232,4 +233,13 @@ extern void print_commit_list(struct commit_list *list, const char *format_cur, const char *format_last); +/* + * Check the signature of the given commit. The result of the check is stored in + * sig->result, 'G' for a good signature, 'B' for a bad signature and 'N' + * for no signature at all. + * This may allocate memory for sig->gpg_output, sig->gpg_status, sig->signer + * and sig->key. + */ +extern void check_commit_signature(const struct commit* commit, struct signature_check *sigc); + #endif /* COMMIT_H */ diff --git a/gpg-interface.h b/gpg-interface.h index cf990218427..5884aa40529 100644 --- a/gpg-interface.h +++ b/gpg-interface.h @@ -1,6 +1,17 @@ #ifndef GPG_INTERFACE_H #define GPG_INTERFACE_H +struct signature_check { + char *gpg_output; + char *gpg_status; + char result; /* 0 (not checked), + * N (checked but no further result), + * G (good) + * B (bad) */ + char *signer; + char *key; +}; + extern int sign_buffer(struct strbuf *buffer, struct strbuf *signature, const char *signing_key); extern int verify_signed_buffer(const char *payload, size_t payload_size, const char *signature, size_t signature_size, struct strbuf *gpg_output, struct strbuf *gpg_status); extern int git_gpg_config(const char *, const char *, void *); diff --git a/pretty.c b/pretty.c index 41f04e669d3..35b592ad837 100644 --- a/pretty.c +++ b/pretty.c @@ -766,14 +766,7 @@ struct format_commit_context { const struct pretty_print_context *pretty_ctx; unsigned commit_header_parsed:1; unsigned commit_message_parsed:1; - unsigned commit_signature_parsed:1; - struct { - char *gpg_output; - char *gpg_status; - char good_bad; - char *signer; - char *key; - } signature; + struct signature_check signature_check; char *message; size_t width, indent1, indent2; @@ -956,64 +949,6 @@ static void rewrap_message_tail(struct strbuf *sb, c->indent2 = new_indent2; } -static struct { - char result; - const char *check; -} signature_check[] = { - { 'G', "\n[GNUPG:] GOODSIG " }, - { 'B', "\n[GNUPG:] BADSIG " }, -}; - -static void parse_signature_lines(struct format_commit_context *ctx) -{ - const char *buf = ctx->signature.gpg_status; - int i; - - for (i = 0; i < ARRAY_SIZE(signature_check); i++) { - const char *found = strstr(buf, signature_check[i].check); - const char *next; - if (!found) - continue; - ctx->signature.good_bad = signature_check[i].result; - found += strlen(signature_check[i].check); - ctx->signature.key = xmemdupz(found, 16); - found += 17; - next = strchrnul(found, '\n'); - ctx->signature.signer = xmemdupz(found, next - found); - break; - } -} - -static void parse_commit_signature(struct format_commit_context *ctx) -{ - struct strbuf payload = STRBUF_INIT; - struct strbuf signature = STRBUF_INIT; - struct strbuf gpg_output = STRBUF_INIT; - struct strbuf gpg_status = STRBUF_INIT; - int status; - - ctx->commit_signature_parsed = 1; - - if (parse_signed_commit(ctx->commit->object.sha1, - &payload, &signature) <= 0) - goto out; - status = verify_signed_buffer(payload.buf, payload.len, - signature.buf, signature.len, - &gpg_output, &gpg_status); - if (status && !gpg_output.len) - goto out; - ctx->signature.gpg_output = strbuf_detach(&gpg_output, NULL); - ctx->signature.gpg_status = strbuf_detach(&gpg_status, NULL); - parse_signature_lines(ctx); - - out: - strbuf_release(&gpg_status); - strbuf_release(&gpg_output); - strbuf_release(&payload); - strbuf_release(&signature); -} - - static int format_reflog_person(struct strbuf *sb, char part, struct reflog_walk_info *log, @@ -1199,27 +1134,27 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder, } if (placeholder[0] == 'G') { - if (!c->commit_signature_parsed) - parse_commit_signature(c); + if (!c->signature_check.result) + check_commit_signature(c->commit, &(c->signature_check)); switch (placeholder[1]) { case 'G': - if (c->signature.gpg_output) - strbuf_addstr(sb, c->signature.gpg_output); + if (c->signature_check.gpg_output) + strbuf_addstr(sb, c->signature_check.gpg_output); break; case '?': - switch (c->signature.good_bad) { + switch (c->signature_check.result) { case 'G': case 'B': - strbuf_addch(sb, c->signature.good_bad); + strbuf_addch(sb, c->signature_check.result); } break; case 'S': - if (c->signature.signer) - strbuf_addstr(sb, c->signature.signer); + if (c->signature_check.signer) + strbuf_addstr(sb, c->signature_check.signer); break; case 'K': - if (c->signature.key) - strbuf_addstr(sb, c->signature.key); + if (c->signature_check.key) + strbuf_addstr(sb, c->signature_check.key); break; } return 2; @@ -1357,8 +1292,8 @@ void format_commit_message(const struct commit *commit, rewrap_message_tail(sb, &context, 0, 0, 0); logmsg_free(context.message, commit); - free(context.signature.gpg_output); - free(context.signature.signer); + free(context.signature_check.gpg_output); + free(context.signature_check.signer); } static void pp_header(const struct pretty_print_context *pp, From f8aae8d0efccd268babd482f10709b4f86a9f32e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20G=C3=B6tte?= Date: Sun, 31 Mar 2013 18:01:34 +0200 Subject: [PATCH 2/5] commit.c/GPG signature verification: Also look at the first GPG status line MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Sebastian Götte Signed-off-by: Junio C Hamano --- commit.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/commit.c b/commit.c index 66a3f4e8f42..94029c94965 100644 --- a/commit.c +++ b/commit.c @@ -1054,13 +1054,20 @@ static void parse_gpg_output(struct signature_check *sigc) const char *buf = sigc->gpg_status; int i; + /* Iterate over all search strings */ for (i = 0; i < ARRAY_SIZE(sigcheck_gpg_status); i++) { - const char *found = strstr(buf, sigcheck_gpg_status[i].check); - const char *next; - if (!found) - continue; + const char *found, *next; + + if (!prefixcmp(buf, sigcheck_gpg_status[i].check + 1)) { + /* At the very beginning of the buffer */ + found = buf + strlen(sigcheck_gpg_status[i].check + 1); + } else { + found = strstr(buf, sigcheck_gpg_status[i].check); + if (!found) + continue; + found += strlen(sigcheck_gpg_status[i].check); + } sigc->result = sigcheck_gpg_status[i].result; - found += strlen(sigcheck_gpg_status[i].check); sigc->key = xmemdupz(found, 16); found += 17; next = strchrnul(found, '\n'); From efed0022492b81bf59d29193c4ffe96492dd9e9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20G=C3=B6tte?= Date: Sun, 31 Mar 2013 18:02:24 +0200 Subject: [PATCH 3/5] merge/pull: verify GPG signatures of commits being merged MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When --verify-signatures is specified on the command-line of git-merge or git-pull, check whether the commits being merged have good gpg signatures and abort the merge in case they do not. This allows e.g. auto-deployment from untrusted repo hosts. Signed-off-by: Sebastian Götte Signed-off-by: Junio C Hamano --- Documentation/merge-options.txt | 5 +++ builtin/merge.c | 34 ++++++++++++++++++- git-pull.sh | 10 ++++-- t/t7612-merge-verify-signatures.sh | 52 ++++++++++++++++++++++++++++++ 4 files changed, 98 insertions(+), 3 deletions(-) create mode 100755 t/t7612-merge-verify-signatures.sh diff --git a/Documentation/merge-options.txt b/Documentation/merge-options.txt index 0bcbe0ac3c4..31f10675215 100644 --- a/Documentation/merge-options.txt +++ b/Documentation/merge-options.txt @@ -83,6 +83,11 @@ option can be used to override --squash. Pass merge strategy specific option through to the merge strategy. +--verify-signatures:: +--no-verify-signatures:: + Verify that the commits being merged have good GPG signatures and abort the + merge in case they do not. + --summary:: --no-summary:: Synonyms to --stat and --no-stat; these are deprecated and will be diff --git a/builtin/merge.c b/builtin/merge.c index 7c8922c8b0b..e57c42c622b 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -49,7 +49,7 @@ static const char * const builtin_merge_usage[] = { static int show_diffstat = 1, shortlog_len = -1, squash; static int option_commit = 1, allow_fast_forward = 1; static int fast_forward_only, option_edit = -1; -static int allow_trivial = 1, have_message; +static int allow_trivial = 1, have_message, verify_signatures; static int overwrite_ignore = 1; static struct strbuf merge_msg = STRBUF_INIT; static struct strategy **use_strategies; @@ -199,6 +199,8 @@ static struct option builtin_merge_options[] = { OPT_BOOLEAN(0, "ff-only", &fast_forward_only, N_("abort if fast-forward is not possible")), OPT_RERERE_AUTOUPDATE(&allow_rerere_auto), + OPT_BOOL(0, "verify-signatures", &verify_signatures, + N_("Verify that the named commit has a valid GPG signature")), OPT_CALLBACK('s', "strategy", &use_strategies, N_("strategy"), N_("merge strategy to use"), option_parse_strategy), OPT_CALLBACK('X', "strategy-option", &xopts, N_("option=value"), @@ -1233,6 +1235,36 @@ int cmd_merge(int argc, const char **argv, const char *prefix) usage_with_options(builtin_merge_usage, builtin_merge_options); + if (verify_signatures) { + for (p = remoteheads; p; p = p->next) { + struct commit *commit = p->item; + char hex[41]; + struct signature_check signature_check; + memset(&signature_check, 0, sizeof(signature_check)); + + check_commit_signature(commit, &signature_check); + + strcpy(hex, find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV)); + switch (signature_check.result) { + case 'G': + break; + case 'B': + die(_("Commit %s has a bad GPG signature " + "allegedly by %s."), hex, signature_check.signer); + default: /* 'N' */ + die(_("Commit %s does not have a GPG signature."), hex); + } + if (verbosity >= 0 && signature_check.result == 'G') + printf(_("Commit %s has a good GPG signature by %s\n"), + hex, signature_check.signer); + + free(signature_check.gpg_output); + free(signature_check.gpg_status); + free(signature_check.signer); + free(signature_check.key); + } + } + strbuf_addstr(&buf, "merge"); for (p = remoteheads; p; p = p->next) strbuf_addf(&buf, " %s", merge_remote_util(p->item)->name); diff --git a/git-pull.sh b/git-pull.sh index 5d97e97bd95..638aabb7b34 100755 --- a/git-pull.sh +++ b/git-pull.sh @@ -39,7 +39,7 @@ test -z "$(git ls-files -u)" || die_conflict test -f "$GIT_DIR/MERGE_HEAD" && die_merge strategy_args= diffstat= no_commit= squash= no_ff= ff_only= -log_arg= verbosity= progress= recurse_submodules= +log_arg= verbosity= progress= recurse_submodules= verify_signatures= merge_args= edit= curr_branch=$(git symbolic-ref -q HEAD) curr_branch_short="${curr_branch#refs/heads/}" @@ -125,6 +125,12 @@ do --no-recurse-submodules) recurse_submodules=--no-recurse-submodules ;; + --verify-signatures) + verify_signatures=--verify-signatures + ;; + --no-verify-signatures) + verify_signatures=--no-verify-signatures + ;; --d|--dr|--dry|--dry-|--dry-r|--dry-ru|--dry-run) dry_run=--dry-run ;; @@ -283,7 +289,7 @@ true) eval="$eval --onto $merge_head ${oldremoteref:-$merge_head}" ;; *) - eval="git-merge $diffstat $no_commit $edit $squash $no_ff $ff_only" + eval="git-merge $diffstat $no_commit $verify_signatures $edit $squash $no_ff $ff_only" eval="$eval $log_arg $strategy_args $merge_args $verbosity $progress" eval="$eval \"\$merge_name\" HEAD $merge_head" ;; diff --git a/t/t7612-merge-verify-signatures.sh b/t/t7612-merge-verify-signatures.sh new file mode 100755 index 00000000000..6ccfbf367aa --- /dev/null +++ b/t/t7612-merge-verify-signatures.sh @@ -0,0 +1,52 @@ +#!/bin/sh + +test_description='merge signature verification tests' +. ./test-lib.sh +. "$TEST_DIRECTORY/lib-gpg.sh" + +test_expect_success GPG 'create signed commits' ' + echo 1 >file && git add file && + test_tick && git commit -m initial && + git tag initial && + + git checkout -b side-signed && + echo 3 >elif && git add elif && + test_tick && git commit -S -m "signed on side" && + git checkout initial && + + git checkout -b side-unsigned && + echo 3 >foo && git add foo && + test_tick && git commit -m "unsigned on side" && + git checkout initial && + + git checkout -b side-bad && + echo 3 >bar && git add bar && + test_tick && git commit -S -m "bad on side" && + git cat-file commit side-bad >raw && + sed -e "s/bad/forged bad/" raw >forged && + git hash-object -w -t commit forged >forged.commit && + git checkout initial && + + git checkout master +' + +test_expect_success GPG 'merge unsigned commit with verification' ' + test_must_fail git merge --ff-only --verify-signatures side-unsigned 2>mergeerror && + test_i18ngrep "does not have a GPG signature" mergeerror +' + +test_expect_success GPG 'merge commit with bad signature with verification' ' + test_must_fail git merge --ff-only --verify-signatures $(cat forged.commit) 2>mergeerror && + test_i18ngrep "has a bad GPG signature" mergeerror +' + +test_expect_success GPG 'merge signed commit with verification' ' + git merge --verbose --ff-only --verify-signatures side-signed >mergeoutput && + test_i18ngrep "has a good GPG signature" mergeoutput +' + +test_expect_success GPG 'merge commit with bad signature without verification' ' + git merge $(cat forged.commit) +' + +test_done From eb307ae7bb78ccde4e2ac69f302ccf8834883628 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20G=C3=B6tte?= Date: Sun, 31 Mar 2013 18:02:46 +0200 Subject: [PATCH 4/5] merge/pull Check for untrusted good GPG signatures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When --verify-signatures is specified, abort the merge in case a good GPG signature from an untrusted key is encountered. Signed-off-by: Sebastian Götte Signed-off-by: Junio C Hamano --- Documentation/merge-options.txt | 4 ++-- builtin/merge.c | 3 +++ commit.c | 14 +++++++++----- commit.h | 10 +++++----- gpg-interface.h | 1 + t/lib-gpg/pubring.gpg | Bin 1164 -> 2359 bytes t/lib-gpg/random_seed | Bin 600 -> 600 bytes t/lib-gpg/secring.gpg | Bin 1237 -> 3734 bytes t/lib-gpg/trustdb.gpg | Bin 1280 -> 1360 bytes t/t7612-merge-verify-signatures.sh | 9 +++++++++ 10 files changed, 29 insertions(+), 12 deletions(-) diff --git a/Documentation/merge-options.txt b/Documentation/merge-options.txt index 31f10675215..a0f022b41df 100644 --- a/Documentation/merge-options.txt +++ b/Documentation/merge-options.txt @@ -85,8 +85,8 @@ option can be used to override --squash. --verify-signatures:: --no-verify-signatures:: - Verify that the commits being merged have good GPG signatures and abort the - merge in case they do not. + Verify that the commits being merged have good and trusted GPG signatures + and abort the merge in case they do not. --summary:: --no-summary:: diff --git a/builtin/merge.c b/builtin/merge.c index e57c42c622b..bac11d1605c 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -1248,6 +1248,9 @@ int cmd_merge(int argc, const char **argv, const char *prefix) switch (signature_check.result) { case 'G': break; + case 'U': + die(_("Commit %s has an untrusted GPG signature, " + "allegedly by %s."), hex, signature_check.signer); case 'B': die(_("Commit %s has a bad GPG signature " "allegedly by %s."), hex, signature_check.signer); diff --git a/commit.c b/commit.c index 94029c94965..516a4ff7d21 100644 --- a/commit.c +++ b/commit.c @@ -1047,6 +1047,8 @@ static struct { } sigcheck_gpg_status[] = { { 'G', "\n[GNUPG:] GOODSIG " }, { 'B', "\n[GNUPG:] BADSIG " }, + { 'U', "\n[GNUPG:] TRUST_NEVER" }, + { 'U', "\n[GNUPG:] TRUST_UNDEFINED" }, }; static void parse_gpg_output(struct signature_check *sigc) @@ -1068,11 +1070,13 @@ static void parse_gpg_output(struct signature_check *sigc) found += strlen(sigcheck_gpg_status[i].check); } sigc->result = sigcheck_gpg_status[i].result; - sigc->key = xmemdupz(found, 16); - found += 17; - next = strchrnul(found, '\n'); - sigc->signer = xmemdupz(found, next - found); - break; + /* The trust messages are not followed by key/signer information */ + if (sigc->result != 'U') { + sigc->key = xmemdupz(found, 16); + found += 17; + next = strchrnul(found, '\n'); + sigc->signer = xmemdupz(found, next - found); + } } } diff --git a/commit.h b/commit.h index c24b844ad64..87b4b6cc0c0 100644 --- a/commit.h +++ b/commit.h @@ -234,11 +234,11 @@ extern void print_commit_list(struct commit_list *list, const char *format_last); /* - * Check the signature of the given commit. The result of the check is stored in - * sig->result, 'G' for a good signature, 'B' for a bad signature and 'N' - * for no signature at all. - * This may allocate memory for sig->gpg_output, sig->gpg_status, sig->signer - * and sig->key. + * Check the signature of the given commit. The result of the check is stored + * in sig->check_result, 'G' for a good signature, 'U' for a good signature + * from an untrusted signer, 'B' for a bad signature and 'N' for no signature + * at all. This may allocate memory for sig->gpg_output, sig->gpg_status, + * sig->signer and sig->key. */ extern void check_commit_signature(const struct commit* commit, struct signature_check *sigc); diff --git a/gpg-interface.h b/gpg-interface.h index 5884aa40529..a85cb5bc97c 100644 --- a/gpg-interface.h +++ b/gpg-interface.h @@ -6,6 +6,7 @@ struct signature_check { char *gpg_status; char result; /* 0 (not checked), * N (checked but no further result), + * U (untrusted good), * G (good) * B (bad) */ char *signer; diff --git a/t/lib-gpg/pubring.gpg b/t/lib-gpg/pubring.gpg index 83855fa4e1c6c37afe550c17afa1e7971042ded5..1a3c2d487c2fda9169751a3068fa51e853a1e519 100644 GIT binary patch delta 1212 zcmV;t1Vj6b3AYlkj0As~0SyFEOqNFh2mr~8{AU1PG9!Ku9w|}@vpZJPg*#s86v-*O zhafj(DL&&lFzqQ>O;r+6QahGBes9{Fcqzh%Wj2h^{ZjI01*KI0kkAVa%poQL}_zlZ*pX5VIVwYX>((5 za%4bdcwudDY-KKPWpqA?0XPH`0RjLb1p-k_mPY~`0|pBT2nPcK1{DYb2?`4Y76JnS z0v-VZ7k~f?2@qikE`_%uafw)?2m1%-{uDP0Rs1|(F{OVhOSKoH$k!o)x3CO5Z^@El zxGq=+xQGR&r@3$S<0@SUu@@UuxUH%pD3Q-D`?37Vg*xmo<%+KD)(U~k>XU^b+=70V zFr?b3DvlFq^B*d%lz=lr!ch6nQbvcwWCD}n2DT3`r?RDkq=7r}qFvEhrcM8+9eP66QueaUSz6NhphD3O@E(iX7T@2kxV(dXd zxG_$z;qqdhUkGxJ?Pc}MK(elV@oumS)Bxd9CXQA~f9M*#=`sXI><#Mh|Ll%uxJqK}<$ zc)VOU|M7H$nU~Bd&(!9WlLk)V)&z>UY~vSc_rVFe1JAY7ThlG1IzE9z6>ly;9WMdd`2^ zgn2IBiSf%lm^DyQau7lg)pfK8(7<}-iih0o369jT0ssS^s3f2O delta 7 Ocmdlk)Wf->TST*Lrq1x^ggx^+ymwieO!6X=U~ZH@{avIgxdn#ai{)Ou@Qw za}Z!boffEq^fn)n?c=IEnDpt59Lnc)aR*;8Z;k>gh_NW;ka;7Mt@v#sG(!Y9SSXWv zQxd3WlyBr#4ltW6uKOoa6(r3df1VX$cG4`Om6hD-ckaX+Hb_yI?{f`hJQY&k!1cM- zoGeY~(Z7aYn$W06djh?W|CMs>W=k@jgf=P2D1UA1T%vz0oE|0C4Q zc}hUG+ighB{7XSaNw_h;=YtqacQj!O{Nn@K$taZO}!>$t>GMgsw?!=n_#(%X9Ha|$b=H@VstWYe; zPUQh+D!{1C6QsKJEiEJaD@Q3F8s5u<$E+<2(By)JAZSxviTsXg(wKC+O% zzvV{Z>W3*k?r7~pgmmkbw8-x{Am!eeN)z?cwIHcT2jqgiA(SXoCoCKWKX;!3@L_U=aFUm!M<>ILG}$`bfnadAkLQbI-upV7Qwf^OE&N45Pz< zk~^KlzNC6)d@QGv=K5-At&A8FS&MQSR`LB}@R1?A3K1p(vM>7CK}EfFhmBJd&cH^- z(3Ih^`VuoVBB|w~p!Q^#DY%V2A2FhXuLL2!7DhfZ}&;BSAyz=T0#S?2+NET5St@16L?YI?5Io%t>%~nsXUb~*EkptHiN?W{=DRu_s;2u ziHh{2&>;CQO7;>{$DN33_Ef}g+;b<2hIF^p(Y>^riLBb*Y2Xw>F8)jp49&oLKJOic z+V{Lt!_`eKGhyk5Edie{-^#n!TFlsfux*QBRZEh^4SVePPmb{BvF|>sKd2cYg@vKp mVI8jcB1(k(tlt^Kr<{EMs>|b*d70nyVMQcc%xEnE(#Uq3d^-35 diff --git a/t/lib-gpg/secring.gpg b/t/lib-gpg/secring.gpg index d831cd9eb3eee613d3c0e1a71093ae01ea7347e3..82dca8f80bf170fde5705862c3eeb9d994725042 100644 GIT binary patch delta 2524 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 delta 7 OcmbOxdzEv;RTcmY+5;N^ diff --git a/t/lib-gpg/trustdb.gpg b/t/lib-gpg/trustdb.gpg index abace962b8bf84be688a6f27e4ebd0ee7052f210..4879ae9a84650a93a4d15bd6560c5d1b89eb4c2f 100644 GIT binary patch delta 133 zcmZqRy1*sEm|l?1%*@Ej$i%=9=re5@0|Nu&L_y(=>YJDu6*k{umSl_t3LyXw!<>GE>E=lCnYu&C?*vSl0pomb%%dj-dsEA)Mq*Svt$mH(j_twWhW_@KtD1fp6 DE~Fa= delta 52 zcmcb>)xagdm|l?1%*@Ej$iTqhmVVlAqM`Uk^-atZ9rz~(oS3|U#hLd&3{VON0Ad;p ADF6Tf diff --git a/t/t7612-merge-verify-signatures.sh b/t/t7612-merge-verify-signatures.sh index 6ccfbf367aa..21a0bf8fb8c 100755 --- a/t/t7612-merge-verify-signatures.sh +++ b/t/t7612-merge-verify-signatures.sh @@ -27,6 +27,10 @@ test_expect_success GPG 'create signed commits' ' git hash-object -w -t commit forged >forged.commit && git checkout initial && + git checkout -b side-untrusted && + echo 3 >baz && git add baz && + test_tick && git commit -SB7227189 -m "untrusted on side" + git checkout master ' @@ -40,6 +44,11 @@ test_expect_success GPG 'merge commit with bad signature with verification' ' test_i18ngrep "has a bad GPG signature" mergeerror ' +test_expect_success GPG 'merge commit with untrusted signature with verification' ' + test_must_fail git merge --ff-only --verify-signatures side-untrusted 2>mergeerror && + test_i18ngrep "has an untrusted GPG signature" mergeerror +' + test_expect_success GPG 'merge signed commit with verification' ' git merge --verbose --ff-only --verify-signatures side-signed >mergeoutput && test_i18ngrep "has a good GPG signature" mergeoutput From e290c4b944f109aff26cc3db4ae0aec92f3cc126 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20G=C3=B6tte?= Date: Sun, 31 Mar 2013 18:03:22 +0200 Subject: [PATCH 5/5] pretty printing: extend %G? to include 'N' and 'U' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Expand %G? in pretty format strings to 'N' in case of no GPG signature and 'U' in case of a good but untrusted GPG signature in addition to the previous 'G'ood and 'B'ad. This eases writing anyting parsing git-log output. Signed-off-by: Sebastian Götte Signed-off-by: Junio C Hamano --- Documentation/pretty-formats.txt | 3 ++- pretty.c | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt index 293965524e8..afac703f212 100644 --- a/Documentation/pretty-formats.txt +++ b/Documentation/pretty-formats.txt @@ -131,7 +131,8 @@ The placeholders are: - '%B': raw body (unwrapped subject and body) - '%N': commit notes - '%GG': raw verification message from GPG for a signed commit -- '%G?': show either "G" for Good or "B" for Bad for a signed commit +- '%G?': show "G" for a Good signature, "B" for a Bad signature, "U" for a good, + untrusted signature and "N" for no signature - '%GS': show the name of the signer for a signed commit - '%GK': show the key used to sign a signed commit - '%gD': reflog selector, e.g., `refs/stash@{1}` diff --git a/pretty.c b/pretty.c index 35b592ad837..d3a82d22d39 100644 --- a/pretty.c +++ b/pretty.c @@ -1145,6 +1145,8 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder, switch (c->signature_check.result) { case 'G': case 'B': + case 'U': + case 'N': strbuf_addch(sb, c->signature_check.result); } break;