1
0
Fork 0
mirror of https://github.com/git/git.git synced 2024-04-27 08:15:11 +02:00

gpg-interface: add minTrustLevel as a configuration option

Previously, signature verification for merge and pull operations checked
if the key had a trust-level of either TRUST_NEVER or TRUST_UNDEFINED in
verify_merge_signature().  If that was the case, the process die()d.

The other code paths that did signature verification relied entirely on
the return code from check_commit_signature().  And signatures made with
a good key, irregardless of its trust level, was considered valid by
check_commit_signature().

This difference in behavior might induce users to erroneously assume
that the trust level of a key in their keyring is always considered by
Git, even for operations where it is not (e.g. during a verify-commit or
verify-tag).

The way it worked was by gpg-interface.c storing the result from the
key/signature status *and* the lowest-two trust levels in the `result`
member of the signature_check structure (the last of these status lines
that were encountered got written to `result`).  These are documented in
GPG under the subsection `General status codes` and `Key related`,
respectively [1].

The GPG documentation says the following on the TRUST_ status codes [1]:

    """
    These are several similar status codes:

    - TRUST_UNDEFINED <error_token>
    - TRUST_NEVER     <error_token>
    - TRUST_MARGINAL  [0  [<validation_model>]]
    - TRUST_FULLY     [0  [<validation_model>]]
    - TRUST_ULTIMATE  [0  [<validation_model>]]

    For good signatures one of these status lines are emitted to
    indicate the validity of the key used to create the signature.
    The error token values are currently only emitted by gpgsm.
    """

My interpretation is that the trust level is conceptionally different
from the validity of the key and/or signature.  That seems to also have
been the assumption of the old code in check_signature() where a result
of 'G' (as in GOODSIG) and 'U' (as in TRUST_NEVER or TRUST_UNDEFINED)
were both considered a success.

The two cases where a result of 'U' had special meaning were in
verify_merge_signature() (where this caused git to die()) and in
format_commit_one() (where it affected the output of the %G? format
specifier).

I think it makes sense to refactor the processing of TRUST_ status lines
such that users can configure a minimum trust level that is enforced
globally, rather than have individual parts of git (e.g. merge) do it
themselves (except for a grace period with backward compatibility).

I also think it makes sense to not store the trust level in the same
struct member as the key/signature status.  While the presence of a
TRUST_ status code does imply that the signature is good (see the first
paragraph in the included snippet above), as far as I can tell, the
order of the status lines from GPG isn't well-defined; thus it would
seem plausible that the trust level could be overwritten with the
key/signature status if they were stored in the same member of the
signature_check structure.

This patch introduces a new configuration option: gpg.minTrustLevel.  It
consolidates trust-level verification to gpg-interface.c and adds a new
`trust_level` member to the signature_check structure.

Backward-compatibility is maintained by introducing a special case in
verify_merge_signature() such that if no user-configurable
gpg.minTrustLevel is set, then the old behavior of rejecting
TRUST_UNDEFINED and TRUST_NEVER is enforced.  If, on the other hand,
gpg.minTrustLevel is set, then that value overrides the old behavior.

Similarly, the %G? format specifier will continue show 'U' for
signatures made with a key that has a trust level of TRUST_UNDEFINED or
TRUST_NEVER, even though the 'U' character no longer exist in the
`result` member of the signature_check structure.  A new format
specifier, %GT, is also introduced for users that want to show all
possible trust levels for a signature.

Another approach would have been to simply drop the trust-level
requirement in verify_merge_signature().  This would also have made the
behavior consistent with other parts of git that perform signature
verification.  However, requiring a minimum trust level for signing keys
does seem to have a real-world use-case.  For example, the build system
used by the Qubes OS project currently parses the raw output from
verify-tag in order to assert a minimum trust level for keys used to
sign git tags [2].

[1] https://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blob;f=doc/doc/DETAILS;h=bd00006e933ac56719b1edd2478ecd79273eae72;hb=refs/heads/master
[2] 9674c1991d/scripts/verify-git-tag (L43)

Signed-off-by: Hans Jerry Illikainen <hji@dyntopia.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Hans Jerry Illikainen 2019-12-27 13:55:57 +00:00 committed by Junio C Hamano
parent c58ae96fc4
commit 54887b4689
13 changed files with 319 additions and 23 deletions

View File

@ -18,3 +18,18 @@ gpg.<format>.program::
chose. (see `gpg.program` and `gpg.format`) `gpg.program` can still
be used as a legacy synonym for `gpg.openpgp.program`. The default
value for `gpg.x509.program` is "gpgsm".
gpg.minTrustLevel::
Specifies a minimum trust level for signature verification. If
this option is unset, then signature verification for merge
operations require a key with at least `marginal` trust. Other
operations that perform signature verification require a key
with at least `undefined` trust. Setting this option overrides
the required trust-level for all operations. Supported values,
in increasing order of significance:
+
* `undefined`
* `never`
* `marginal`
* `fully`
* `ultimate`

View File

@ -213,6 +213,7 @@ endif::git-rev-list[]
'%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
to sign a signed commit
'%GT':: show the trust level for the key 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 for the
`-g` option. The portion before the `@` is the refname as

View File

@ -62,6 +62,7 @@ static int show_diffstat = 1, shortlog_len = -1, squash;
static int option_commit = -1;
static int option_edit = -1;
static int allow_trivial = 1, have_message, verify_signatures;
static int check_trust_level = 1;
static int overwrite_ignore = 1;
static struct strbuf merge_msg = STRBUF_INIT;
static struct strategy **use_strategies;
@ -631,6 +632,8 @@ static int git_merge_config(const char *k, const char *v, void *cb)
} else if (!strcmp(k, "commit.gpgsign")) {
sign_commit = git_config_bool(k, v) ? "" : NULL;
return 0;
} else if (!strcmp(k, "gpg.mintrustlevel")) {
check_trust_level = 0;
}
status = fmt_merge_msg_config(k, v, cb);
@ -1397,7 +1400,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
die(_("Can merge only exactly one commit into empty head"));
if (verify_signatures)
verify_merge_signature(remoteheads->item, verbosity);
verify_merge_signature(remoteheads->item, verbosity,
check_trust_level);
remote_head_oid = &remoteheads->item->object.oid;
read_empty(remote_head_oid, 0);
@ -1420,7 +1424,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
if (verify_signatures) {
for (p = remoteheads; p; p = p->next) {
verify_merge_signature(p->item, verbosity);
verify_merge_signature(p->item, verbosity,
check_trust_level);
}
}

View File

@ -107,6 +107,7 @@ static char *opt_ff;
static char *opt_verify_signatures;
static int opt_autostash = -1;
static int config_autostash;
static int check_trust_level = 1;
static struct argv_array opt_strategies = ARGV_ARRAY_INIT;
static struct argv_array opt_strategy_opts = ARGV_ARRAY_INIT;
static char *opt_gpg_sign;
@ -355,6 +356,8 @@ static enum rebase_type config_get_rebase(void)
*/
static int git_pull_config(const char *var, const char *value, void *cb)
{
int status;
if (!strcmp(var, "rebase.autostash")) {
config_autostash = git_config_bool(var, value);
return 0;
@ -362,7 +365,14 @@ static int git_pull_config(const char *var, const char *value, void *cb)
recurse_submodules = git_config_bool(var, value) ?
RECURSE_SUBMODULES_ON : RECURSE_SUBMODULES_OFF;
return 0;
} else if (!strcmp(var, "gpg.mintrustlevel")) {
check_trust_level = 0;
}
status = git_gpg_config(var, value, cb);
if (status)
return status;
return git_default_config(var, value, cb);
}
@ -587,7 +597,8 @@ static int pull_into_void(const struct object_id *merge_head,
die(_("unable to access commit %s"),
oid_to_hex(merge_head));
verify_merge_signature(commit, opt_verbosity);
verify_merge_signature(commit, opt_verbosity,
check_trust_level);
}
/*

View File

@ -1136,21 +1136,23 @@ int check_commit_signature(const struct commit *commit, struct signature_check *
return ret;
}
void verify_merge_signature(struct commit *commit, int verbosity)
void verify_merge_signature(struct commit *commit, int verbosity,
int check_trust)
{
char hex[GIT_MAX_HEXSZ + 1];
struct signature_check signature_check;
int ret;
memset(&signature_check, 0, sizeof(signature_check));
check_commit_signature(commit, &signature_check);
ret = check_commit_signature(commit, &signature_check);
find_unique_abbrev_r(hex, &commit->object.oid, DEFAULT_ABBREV);
switch (signature_check.result) {
case 'G':
if (ret || (check_trust && signature_check.trust_level < TRUST_MARGINAL))
die(_("Commit %s has an untrusted GPG signature, "
"allegedly by %s."), hex, signature_check.signer);
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);

View File

@ -383,8 +383,18 @@ int compare_commits_by_author_date(const void *a_, const void *b_, void *unused)
* Verify a single commit with check_commit_signature() and die() if it is not
* a good signature. This isn't really suitable for general use, but is a
* helper to implement consistent logic for pull/merge --verify-signatures.
*
* The check_trust parameter is meant for backward-compatibility. The GPG
* interface verifies key trust with a default trust level that is below the
* default trust level for merge operations. Its value should be non-zero if
* the user hasn't set a minimum trust level explicitly in their configuration.
*
* If the user has set a minimum trust level, then that value should be obeyed
* and check_trust should be zero, even if the configured trust level is below
* the default trust level for merges.
*/
void verify_merge_signature(struct commit *commit, int verbose);
void verify_merge_signature(struct commit *commit, int verbose,
int check_trust);
int compare_commits_by_commit_date(const void *a_, const void *b_, void *unused);
int compare_commits_by_gen_then_commit_date(const void *a_, const void *b_, void *unused);

View File

@ -7,6 +7,8 @@
#include "tempfile.h"
static char *configured_signing_key;
static enum signature_trust_level configured_min_trust_level = TRUST_UNDEFINED;
struct gpg_format {
const char *name;
const char *program;
@ -85,6 +87,8 @@ void signature_check_clear(struct signature_check *sigc)
#define GPG_STATUS_UID (1<<2)
/* The status includes key fingerprints */
#define GPG_STATUS_FINGERPRINT (1<<3)
/* The status includes trust level */
#define GPG_STATUS_TRUST_LEVEL (1<<4)
/* Short-hand for standard exclusive *SIG status with keyid & UID */
#define GPG_STATUS_STDSIG (GPG_STATUS_EXCLUSIVE|GPG_STATUS_KEYID|GPG_STATUS_UID)
@ -96,13 +100,23 @@ static struct {
} sigcheck_gpg_status[] = {
{ 'G', "GOODSIG ", GPG_STATUS_STDSIG },
{ 'B', "BADSIG ", GPG_STATUS_STDSIG },
{ 'U', "TRUST_NEVER", 0 },
{ 'U', "TRUST_UNDEFINED", 0 },
{ 'E', "ERRSIG ", GPG_STATUS_EXCLUSIVE|GPG_STATUS_KEYID },
{ 'X', "EXPSIG ", GPG_STATUS_STDSIG },
{ 'Y', "EXPKEYSIG ", GPG_STATUS_STDSIG },
{ 'R', "REVKEYSIG ", GPG_STATUS_STDSIG },
{ 0, "VALIDSIG ", GPG_STATUS_FINGERPRINT },
{ 0, "TRUST_", GPG_STATUS_TRUST_LEVEL },
};
static struct {
const char *key;
enum signature_trust_level value;
} sigcheck_gpg_trust_level[] = {
{ "UNDEFINED", TRUST_UNDEFINED },
{ "NEVER", TRUST_NEVER },
{ "MARGINAL", TRUST_MARGINAL },
{ "FULLY", TRUST_FULLY },
{ "ULTIMATE", TRUST_ULTIMATE },
};
static void replace_cstring(char **field, const char *line, const char *next)
@ -115,6 +129,20 @@ static void replace_cstring(char **field, const char *line, const char *next)
*field = NULL;
}
static int parse_gpg_trust_level(const char *level,
enum signature_trust_level *res)
{
size_t i;
for (i = 0; i < ARRAY_SIZE(sigcheck_gpg_trust_level); i++) {
if (!strcmp(sigcheck_gpg_trust_level[i].key, level)) {
*res = sigcheck_gpg_trust_level[i].value;
return 0;
}
}
return 1;
}
static void parse_gpg_output(struct signature_check *sigc)
{
const char *buf = sigc->gpg_status;
@ -136,9 +164,18 @@ static void parse_gpg_output(struct signature_check *sigc)
/* Iterate over all search strings */
for (i = 0; i < ARRAY_SIZE(sigcheck_gpg_status); i++) {
if (skip_prefix(line, sigcheck_gpg_status[i].check, &line)) {
/*
* GOODSIG, BADSIG etc. can occur only once for
* each signature. Therefore, if we had more
* than one then we're dealing with multiple
* signatures. We don't support them
* currently, and they're rather hard to
* create, so something is likely fishy and we
* should reject them altogether.
*/
if (sigcheck_gpg_status[i].flags & GPG_STATUS_EXCLUSIVE) {
if (seen_exclusive_status++)
goto found_duplicate_status;
goto error;
}
if (sigcheck_gpg_status[i].result)
@ -154,6 +191,25 @@ static void parse_gpg_output(struct signature_check *sigc)
replace_cstring(&sigc->signer, line, next);
}
}
/* Do we have trust level? */
if (sigcheck_gpg_status[i].flags & GPG_STATUS_TRUST_LEVEL) {
/*
* GPG v1 and v2 differs in how the
* TRUST_ lines are written. Some
* trust lines contain no additional
* space-separated information for v1.
*/
size_t trust_size = strcspn(line, " \n");
char *trust = xmemdupz(line, trust_size);
if (parse_gpg_trust_level(trust, &sigc->trust_level)) {
free(trust);
goto error;
}
free(trust);
}
/* Do we have fingerprint? */
if (sigcheck_gpg_status[i].flags & GPG_STATUS_FINGERPRINT) {
const char *limit;
@ -191,14 +247,7 @@ static void parse_gpg_output(struct signature_check *sigc)
}
return;
found_duplicate_status:
/*
* GOODSIG, BADSIG etc. can occur only once for each signature.
* Therefore, if we had more than one then we're dealing with multiple
* signatures. We don't support them currently, and they're rather
* hard to create, so something is likely fishy and we should reject
* them altogether.
*/
error:
sigc->result = 'E';
/* Clear partial data to avoid confusion */
FREE_AND_NULL(sigc->primary_key_fingerprint);
@ -215,6 +264,7 @@ int check_signature(const char *payload, size_t plen, const char *signature,
int status;
sigc->result = 'N';
sigc->trust_level = -1;
status = verify_signed_buffer(payload, plen, signature, slen,
&gpg_output, &gpg_status);
@ -224,7 +274,8 @@ int check_signature(const char *payload, size_t plen, const char *signature,
sigc->gpg_output = strbuf_detach(&gpg_output, NULL);
sigc->gpg_status = strbuf_detach(&gpg_status, NULL);
parse_gpg_output(sigc);
status |= sigc->result != 'G' && sigc->result != 'U';
status |= sigc->result != 'G';
status |= sigc->trust_level < configured_min_trust_level;
out:
strbuf_release(&gpg_status);
@ -271,6 +322,8 @@ int git_gpg_config(const char *var, const char *value, void *cb)
{
struct gpg_format *fmt = NULL;
char *fmtname = NULL;
char *trust;
int ret;
if (!strcmp(var, "user.signingkey")) {
if (!value)
@ -290,6 +343,20 @@ int git_gpg_config(const char *var, const char *value, void *cb)
return 0;
}
if (!strcmp(var, "gpg.mintrustlevel")) {
if (!value)
return config_error_nonbool(var);
trust = xstrdup_toupper(value);
ret = parse_gpg_trust_level(trust, &configured_min_trust_level);
free(trust);
if (ret)
return error("unsupported value for %s: %s", var,
value);
return 0;
}
if (!strcmp(var, "gpg.program") || !strcmp(var, "gpg.openpgp.program"))
fmtname = "openpgp";

View File

@ -7,6 +7,14 @@ struct strbuf;
#define GPG_VERIFY_RAW 2
#define GPG_VERIFY_OMIT_STATUS 4
enum signature_trust_level {
TRUST_UNDEFINED,
TRUST_NEVER,
TRUST_MARGINAL,
TRUST_FULLY,
TRUST_ULTIMATE,
};
struct signature_check {
char *payload;
char *gpg_output;
@ -16,7 +24,6 @@ struct signature_check {
* possible "result":
* 0 (not checked)
* N (checked but no further result)
* U (untrusted good)
* G (good)
* B (bad)
*/
@ -25,6 +32,7 @@ struct signature_check {
char *key;
char *fingerprint;
char *primary_key_fingerprint;
enum signature_trust_level trust_level;
};
void signature_check_clear(struct signature_check *sigc);

View File

@ -1303,9 +1303,18 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
case '?':
switch (c->signature_check.result) {
case 'G':
switch (c->signature_check.trust_level) {
case TRUST_UNDEFINED:
case TRUST_NEVER:
strbuf_addch(sb, 'U');
break;
default:
strbuf_addch(sb, 'G');
break;
}
break;
case 'B':
case 'E':
case 'U':
case 'N':
case 'X':
case 'Y':
@ -1329,6 +1338,25 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
if (c->signature_check.primary_key_fingerprint)
strbuf_addstr(sb, c->signature_check.primary_key_fingerprint);
break;
case 'T':
switch (c->signature_check.trust_level) {
case TRUST_UNDEFINED:
strbuf_addstr(sb, "undefined");
break;
case TRUST_NEVER:
strbuf_addstr(sb, "never");
break;
case TRUST_MARGINAL:
strbuf_addstr(sb, "marginal");
break;
case TRUST_FULLY:
strbuf_addstr(sb, "fully");
break;
case TRUST_ULTIMATE:
strbuf_addstr(sb, "ultimate");
break;
}
break;
default:
return 0;
}

View File

@ -60,6 +60,27 @@ test_expect_success GPG 'pull commit with untrusted signature with --verify-sign
test_i18ngrep "has an untrusted GPG signature" pullerror
'
test_expect_success GPG 'pull commit with untrusted signature with --verify-signatures and minTrustLevel=ultimate' '
test_when_finished "git reset --hard && git checkout initial" &&
test_config gpg.minTrustLevel ultimate &&
test_must_fail git pull --ff-only --verify-signatures untrusted 2>pullerror &&
test_i18ngrep "has an untrusted GPG signature" pullerror
'
test_expect_success GPG 'pull commit with untrusted signature with --verify-signatures and minTrustLevel=marginal' '
test_when_finished "git reset --hard && git checkout initial" &&
test_config gpg.minTrustLevel marginal &&
test_must_fail git pull --ff-only --verify-signatures untrusted 2>pullerror &&
test_i18ngrep "has an untrusted GPG signature" pullerror
'
test_expect_success GPG 'pull commit with untrusted signature with --verify-signatures and minTrustLevel=undefined' '
test_when_finished "git reset --hard && git checkout initial" &&
test_config gpg.minTrustLevel undefined &&
git pull --ff-only --verify-signatures untrusted >pulloutput &&
test_i18ngrep "has a good GPG signature" pulloutput
'
test_expect_success GPG 'pull signed commit with --verify-signatures' '
test_when_finished "git reset --hard && git checkout initial" &&
git pull --verify-signatures signed >pulloutput &&
@ -79,10 +100,53 @@ test_expect_success GPG 'pull commit with bad signature with --no-verify-signatu
'
test_expect_success GPG 'pull unsigned commit into unborn branch' '
test_when_finished "rm -rf empty-repo" &&
git init empty-repo &&
test_must_fail \
git -C empty-repo pull --verify-signatures .. 2>pullerror &&
test_i18ngrep "does not have a GPG signature" pullerror
'
test_expect_success GPG 'pull commit into unborn branch with bad signature and --verify-signatures' '
test_when_finished "rm -rf empty-repo" &&
git init empty-repo &&
test_must_fail \
git -C empty-repo pull --ff-only --verify-signatures ../bad 2>pullerror &&
test_i18ngrep "has a bad GPG signature" pullerror
'
test_expect_success GPG 'pull commit into unborn branch with untrusted signature and --verify-signatures' '
test_when_finished "rm -rf empty-repo" &&
git init empty-repo &&
test_must_fail \
git -C empty-repo pull --ff-only --verify-signatures ../untrusted 2>pullerror &&
test_i18ngrep "has an untrusted GPG signature" pullerror
'
test_expect_success GPG 'pull commit into unborn branch with untrusted signature and --verify-signatures and minTrustLevel=ultimate' '
test_when_finished "rm -rf empty-repo" &&
git init empty-repo &&
test_config_global gpg.minTrustLevel ultimate &&
test_must_fail \
git -C empty-repo pull --ff-only --verify-signatures ../untrusted 2>pullerror &&
test_i18ngrep "has an untrusted GPG signature" pullerror
'
test_expect_success GPG 'pull commit into unborn branch with untrusted signature and --verify-signatures and minTrustLevel=marginal' '
test_when_finished "rm -rf empty-repo" &&
git init empty-repo &&
test_config_global gpg.minTrustLevel marginal &&
test_must_fail \
git -C empty-repo pull --ff-only --verify-signatures ../untrusted 2>pullerror &&
test_i18ngrep "has an untrusted GPG signature" pullerror
'
test_expect_success GPG 'pull commit into unborn branch with untrusted signature and --verify-signatures and minTrustLevel=undefined' '
test_when_finished "rm -rf empty-repo" &&
git init empty-repo &&
test_config_global gpg.minTrustLevel undefined &&
git -C empty-repo pull --ff-only --verify-signatures ../untrusted >pulloutput &&
test_i18ngrep "has a good GPG signature" pulloutput
'
test_done

View File

@ -86,6 +86,30 @@ test_expect_success GPGSM 'verify and show signatures x509' '
echo ninth-signed-x509 OK
'
test_expect_success GPGSM 'verify and show signatures x509 with low minTrustLevel' '
test_config gpg.minTrustLevel undefined &&
git verify-tag ninth-signed-x509 2>actual &&
grep "Good signature from" actual &&
! grep "BAD signature from" actual &&
echo ninth-signed-x509 OK
'
test_expect_success GPGSM 'verify and show signatures x509 with matching minTrustLevel' '
test_config gpg.minTrustLevel fully &&
git verify-tag ninth-signed-x509 2>actual &&
grep "Good signature from" actual &&
! grep "BAD signature from" actual &&
echo ninth-signed-x509 OK
'
test_expect_success GPGSM 'verify and show signatures x509 with high minTrustLevel' '
test_config gpg.minTrustLevel ultimate &&
test_must_fail git verify-tag ninth-signed-x509 2>actual &&
grep "Good signature from" actual &&
! grep "BAD signature from" actual &&
echo ninth-signed-x509 OK
'
test_expect_success GPG 'detect fudged signature' '
git cat-file tag seventh-signed >raw &&
sed -e "/^tag / s/seventh/7th forged/" raw >forged1 &&

View File

@ -109,6 +109,21 @@ test_expect_success GPG 'verify-commit exits success on untrusted signature' '
grep "not certified" actual
'
test_expect_success GPG 'verify-commit exits success with matching minTrustLevel' '
test_config gpg.minTrustLevel ultimate &&
git verify-commit sixth-signed
'
test_expect_success GPG 'verify-commit exits success with low minTrustLevel' '
test_config gpg.minTrustLevel fully &&
git verify-commit sixth-signed
'
test_expect_success GPG 'verify-commit exits failure with high minTrustLevel' '
test_config gpg.minTrustLevel ultimate &&
test_must_fail git verify-commit eighth-signed-alt
'
test_expect_success GPG 'verify signatures with --raw' '
(
for commit in initial second merge fourth-signed fifth-signed sixth-signed seventh-signed
@ -219,6 +234,30 @@ test_expect_success GPG 'show untrusted signature with custom format' '
test_cmp expect actual
'
test_expect_success GPG 'show untrusted signature with undefined trust level' '
cat >expect <<-\EOF &&
undefined
65A0EEA02E30CAD7
Eris Discordia <discord@example.net>
F8364A59E07FFE9F4D63005A65A0EEA02E30CAD7
D4BE22311AD3131E5EDA29A461092E85B7227189
EOF
git log -1 --format="%GT%n%GK%n%GS%n%GF%n%GP" eighth-signed-alt >actual &&
test_cmp expect actual
'
test_expect_success GPG 'show untrusted signature with ultimate trust level' '
cat >expect <<-\EOF &&
ultimate
13B6F51ECDDE430D
C O Mitter <committer@example.com>
73D758744BE721698EC54E8713B6F51ECDDE430D
73D758744BE721698EC54E8713B6F51ECDDE430D
EOF
git log -1 --format="%GT%n%GK%n%GS%n%GF%n%GP" sixth-signed >actual &&
test_cmp expect actual
'
test_expect_success GPG 'show unknown signature with custom format' '
cat >expect <<-\EOF &&
E

View File

@ -66,6 +66,20 @@ test_expect_success GPG 'merge commit with untrusted signature with verification
test_i18ngrep "has an untrusted GPG signature" mergeerror
'
test_expect_success GPG 'merge commit with untrusted signature with verification and high minTrustLevel' '
test_when_finished "git reset --hard && git checkout initial" &&
test_config gpg.minTrustLevel marginal &&
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 commit with untrusted signature with verification and low minTrustLevel' '
test_when_finished "git reset --hard && git checkout initial" &&
test_config gpg.minTrustLevel undefined &&
git merge --ff-only --verify-signatures side-untrusted >mergeoutput &&
test_i18ngrep "has a good GPG signature" mergeoutput
'
test_expect_success GPG 'merge commit with untrusted signature with merge.verifySignatures=true' '
test_when_finished "git reset --hard && git checkout initial" &&
test_config merge.verifySignatures true &&
@ -73,6 +87,14 @@ test_expect_success GPG 'merge commit with untrusted signature with merge.verify
test_i18ngrep "has an untrusted GPG signature" mergeerror
'
test_expect_success GPG 'merge commit with untrusted signature with merge.verifySignatures=true and minTrustLevel' '
test_when_finished "git reset --hard && git checkout initial" &&
test_config merge.verifySignatures true &&
test_config gpg.minTrustLevel marginal &&
test_must_fail git merge --ff-only side-untrusted 2>mergeerror &&
test_i18ngrep "has an untrusted GPG signature" mergeerror
'
test_expect_success GPG 'merge signed commit with verification' '
test_when_finished "git reset --hard && git checkout initial" &&
git merge --verbose --ff-only --verify-signatures side-signed >mergeoutput &&