credential: let helpers tell us to quit

When we are trying to fill a credential, we loop over the
set of defined credential-helpers, then fall back to running
askpass, and then finally prompt on the terminal. Helpers
which cannot find a credential are free to tell us nothing,
but they cannot currently ask us to stop prompting.

This patch lets them provide a "quit" attribute, which asks
us to stop the process entirely (avoiding running more
helpers, as well as the askpass/terminal prompt).

This has a few possible uses:

  1. A helper which prompts the user itself (e.g., in a
     dialog) can provide a "cancel" button to the user to
     stop further prompts.

  2. Some helpers may know that prompting cannot possibly
     work. For example, if their role is to broker a ticket
     from an external auth system and that auth system
     cannot be contacted, there is no point in continuing
     (we need a ticket to authenticate, and the user cannot
     provide one by typing it in).

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Jeff King 2014-12-03 22:46:48 -05:00 committed by Junio C Hamano
parent 7fa1365c54
commit 59b386526a
4 changed files with 19 additions and 1 deletions

View File

@ -248,7 +248,10 @@ FORMAT` in linkgit:git-credential[7] for a detailed specification).
For a `get` operation, the helper should produce a list of attributes For a `get` operation, the helper should produce a list of attributes
on stdout in the same format. A helper is free to produce a subset, or on stdout in the same format. A helper is free to produce a subset, or
even no values at all if it has nothing useful to provide. Any provided even no values at all if it has nothing useful to provide. Any provided
attributes will overwrite those already known about by Git. attributes will overwrite those already known about by Git. If a helper
outputs a `quit` attribute with a value of `true` or `1`, no further
helpers will be consulted, nor will the user be prompted (if no
credential has been provided, the operation will then fail).
For a `store` or `erase` operation, the helper's output is ignored. For a `store` or `erase` operation, the helper's output is ignored.
If it fails to perform the requested operation, it may complain to If it fails to perform the requested operation, it may complain to

View File

@ -173,6 +173,8 @@ int credential_read(struct credential *c, FILE *fp)
c->path = xstrdup(value); c->path = xstrdup(value);
} else if (!strcmp(key, "url")) { } else if (!strcmp(key, "url")) {
credential_from_url(c, value); credential_from_url(c, value);
} else if (!strcmp(key, "quit")) {
c->quit = !!git_config_bool("quit", value);
} }
/* /*
* Ignore other lines; we don't know what they mean, but * Ignore other lines; we don't know what they mean, but
@ -275,6 +277,9 @@ void credential_fill(struct credential *c)
credential_do(c, c->helpers.items[i].string, "get"); credential_do(c, c->helpers.items[i].string, "get");
if (c->username && c->password) if (c->username && c->password)
return; return;
if (c->quit)
die("credential helper '%s' told us to quit",
c->helpers.items[i].string);
} }
credential_getpass(c); credential_getpass(c);

View File

@ -7,6 +7,7 @@ struct credential {
struct string_list helpers; struct string_list helpers;
unsigned approved:1, unsigned approved:1,
configured:1, configured:1,
quit:1,
use_http_path:1; use_http_path:1;
char *username; char *username;

View File

@ -289,4 +289,13 @@ test_expect_success 'http paths can be part of context' '
EOF EOF
' '
test_expect_success 'helpers can abort the process' '
test_must_fail git \
-c credential.helper="!f() { echo quit=1; }; f" \
-c credential.helper="verbatim foo bar" \
credential fill >stdout &&
>expect &&
test_cmp expect stdout
'
test_done test_done