diff --git a/Documentation/git-credential.txt b/Documentation/git-credential.txt index 3d3accc273..e41493292f 100644 --- a/Documentation/git-credential.txt +++ b/Documentation/git-credential.txt @@ -8,7 +8,7 @@ git-credential - Retrieve and store user credentials SYNOPSIS -------- ------------------ -'git credential' (fill|approve|reject) +'git credential' (fill|approve|reject|capability) ------------------ DESCRIPTION @@ -41,6 +41,9 @@ If the action is `reject`, git-credential will send the description to any configured credential helpers, which may erase any stored credentials matching the description. +If the action is `capability`, git-credential will announce any capabilities +it supports to standard output. + If the action is `approve` or `reject`, no output should be emitted. TYPICAL USE OF GIT CREDENTIAL @@ -263,6 +266,29 @@ is supported, but they should not be provided without the capability. Unrecognised attributes and capabilities are silently discarded. +[[CAPA-IOFMT]] +CAPABILITY INPUT/OUTPUT FORMAT +------------------------------ + +For `git credential capability`, the format is slightly different. First, a +`version 0` announcement is made to indicate the current version of the +protocol, and then each capability is announced with a line like `capability +authtype`. Credential helpers may also implement this format, again with the +`capability` argument. Additional lines may be added in the future; callers +should ignore lines which they don't understand. + +Because this is a new part of the credential helper protocol, older versions of +Git, as well as some credential helpers, may not support it. If a non-zero +exit status is received, or if the first line doesn't start with the word +`version` and a space, callers should assume that no capabilities are supported. + +The intention of this format is to differentiate it from the credential output +in an unambiguous way. It is possible to use very simple credential helpers +(e.g., inline shell scripts) which always produce identical output. Using a +distinct format allows users to continue to use this syntax without having to +worry about correctly implementing capability advertisements or accidentally +confusing callers querying for capabilities. + GIT --- Part of the linkgit:git[1] suite diff --git a/builtin/credential-cache.c b/builtin/credential-cache.c index bba96d4ffd..f5c989e2b2 100644 --- a/builtin/credential-cache.c +++ b/builtin/credential-cache.c @@ -1,4 +1,5 @@ #include "builtin.h" +#include "credential.h" #include "gettext.h" #include "parse-options.h" #include "path.h" @@ -127,6 +128,13 @@ static char *get_socket_path(void) return socket; } +static void announce_capabilities(void) +{ + struct credential c = CREDENTIAL_INIT; + c.capa_authtype.request_initial = 1; + credential_announce_capabilities(&c, stdout); +} + int cmd_credential_cache(int argc, const char **argv, const char *prefix) { char *socket_path = NULL; @@ -160,6 +168,8 @@ int cmd_credential_cache(int argc, const char **argv, const char *prefix) do_cache(socket_path, op, timeout, FLAG_RELAY); else if (!strcmp(op, "store")) do_cache(socket_path, op, timeout, FLAG_RELAY|FLAG_SPAWN); + else if (!strcmp(op, "capability")) + announce_capabilities(); else ; /* ignore unknown operation */ diff --git a/builtin/credential.c b/builtin/credential.c index 3568e57025..5100d441f2 100644 --- a/builtin/credential.c +++ b/builtin/credential.c @@ -17,6 +17,12 @@ int cmd_credential(int argc, const char **argv, const char *prefix UNUSED) usage(usage_msg); op = argv[1]; + if (!strcmp(op, "capability")) { + credential_set_all_capabilities(&c, CREDENTIAL_OP_INITIAL); + credential_announce_capabilities(&c, stdout); + return 0; + } + if (credential_read(&c, stdin, CREDENTIAL_OP_INITIAL) < 0) die("unable to read credential from stdin"); diff --git a/credential.c b/credential.c index ffaf31499e..758528b291 100644 --- a/credential.c +++ b/credential.c @@ -72,6 +72,17 @@ void credential_set_all_capabilities(struct credential *c, credential_set_capability(&c->capa_state, op_type); } +static void announce_one(struct credential_capability *cc, const char *name, FILE *fp) { + if (cc->request_initial) + fprintf(fp, "capability %s\n", name); +} + +void credential_announce_capabilities(struct credential *c, FILE *fp) { + fprintf(fp, "version 0\n"); + announce_one(&c->capa_authtype, "authtype", fp); + announce_one(&c->capa_state, "state", fp); +} + int credential_match(const struct credential *want, const struct credential *have, int match_password) { diff --git a/credential.h b/credential.h index f8df10937c..af8c287ff2 100644 --- a/credential.h +++ b/credential.h @@ -253,6 +253,12 @@ void credential_set_all_capabilities(struct credential *c, */ void credential_clear_secrets(struct credential *c); +/** + * Print a list of supported capabilities and version numbers to standard + * output. + */ +void credential_announce_capabilities(struct credential *c, FILE *fp); + /** * Prepares the credential for the next iteration of the helper protocol by * updating the state headers to send with the ones read by the last iteration