Skip to content

Commit e30b2fe

Browse files
Javier Roucher Iglesiasgitster
authored andcommitted
add 'git credential' plumbing command
The credential API is in C, and not available to scripting languages. Expose the functionalities of the API by wrapping them into a new plumbing command "git credentials". In other words, replace the internal "test-credential" by an official Git command. Most documentation writen by: Jeff King <peff@peff.net> Signed-off-by: Pavel Volek <Pavel.Volek@ensimag.imag.fr> Signed-off-by: Kim Thuat Nguyen <Kim-Thuat.Nguyen@ensimag.imag.fr> Signed-off-by: Javier Roucher Iglesias <Javier.Roucher-Iglesias@ensimag.imag.fr> Signed-off-by: Matthieu Moy <Matthieu.Moy@imag.fr> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent fd37807 commit e30b2fe

File tree

8 files changed

+163
-52
lines changed

8 files changed

+163
-52
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
/git-commit-tree
3232
/git-config
3333
/git-count-objects
34+
/git-credential
3435
/git-credential-cache
3536
/git-credential-cache--daemon
3637
/git-credential-store
@@ -172,7 +173,6 @@
172173
/gitweb/static/gitweb.js
173174
/gitweb/static/gitweb.min.*
174175
/test-chmtime
175-
/test-credential
176176
/test-ctype
177177
/test-date
178178
/test-delta

Documentation/git-credential.txt

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
git-credential(1)
2+
=================
3+
4+
NAME
5+
----
6+
git-credential - retrieve and store user credentials
7+
8+
SYNOPSIS
9+
--------
10+
------------------
11+
git credential <fill|approve|reject>
12+
------------------
13+
14+
DESCRIPTION
15+
-----------
16+
17+
Git has an internal interface for storing and retrieving credentials
18+
from system-specific helpers, as well as prompting the user for
19+
usernames and passwords. The git-credential command exposes this
20+
interface to scripts which may want to retrieve, store, or prompt for
21+
credentials in the same manner as git. The design of this scriptable
22+
interface models the internal C API; see
23+
link:technical/api-credentials.txt[the git credential API] for more
24+
background on the concepts.
25+
26+
git-credential takes an "action" option on the command-line (one of
27+
`fill`, `approve`, or `reject`) and reads a credential description
28+
on stdin (see <<IOFMT,INPUT/OUTPUT FORMAT>>).
29+
30+
If the action is `fill`, git-credential will attempt to add "username"
31+
and "password" attributes to the description by reading config files,
32+
by contacting any configured credential helpers, or by prompting the
33+
user. The username and password attributes of the credential
34+
description are then printed to stdout together with the attributes
35+
already provided.
36+
37+
If the action is `approve`, git-credential will send the description
38+
to any configured credential helpers, which may store the credential
39+
for later use.
40+
41+
If the action is `reject`, git-credential will send the description to
42+
any configured credential helpers, which may erase any stored
43+
credential matching the description.
44+
45+
If the action is `approve` or `reject`, no output should be emitted.
46+
47+
TYPICAL USE OF GIT CREDENTIAL
48+
-----------------------------
49+
50+
An application using git-credential will typically use `git
51+
credential` following these steps:
52+
53+
1. Generate a credential description based on the context.
54+
+
55+
For example, if we want a password for
56+
`https://example.com/foo.git`, we might generate the following
57+
credential description (don't forget the blank line at the end; it
58+
tells `git credential` that the application finished feeding all the
59+
infomation it has):
60+
61+
protocol=https
62+
host=example.com
63+
path=foo.git
64+
65+
2. Ask git-credential to give us a username and password for this
66+
description. This is done by running `git credential fill`,
67+
feeding the description from step (1) to its standard input. The
68+
credential will be produced on standard output, like:
69+
70+
username=bob
71+
password=secr3t
72+
+
73+
If the `git credential` knew about the password, this step may
74+
not have involved the user actually typing this password (the
75+
user may have typed a password to unlock the keychain instead,
76+
or no user interaction was done if the keychain was already
77+
unlocked) before it returned `password=secr3t`.
78+
79+
3. Use the credential (e.g., access the URL with the username and
80+
password from step (2)), and see if it's accepted.
81+
82+
4. Report on the success or failure of the password. If the
83+
credential allowed the operation to complete successfully, then
84+
it can be marked with an "approve" action to tell `git
85+
credential` to reuse it in its next invocation. If the credential
86+
was rejected during the operation, use the "reject" action so
87+
that `git credential` will ask for a new password in its next
88+
invocation. In either case, `git credential` should be fed with
89+
the credential description obtained from step (2) together with
90+
the ones already provided in step (1).
91+
92+
[[IOFMT]]
93+
INPUT/OUTPUT FORMAT
94+
-------------------
95+
96+
`git credential` reads and/or writes (depending on the action used)
97+
credential information in its standard input/output. These information
98+
can correspond either to keys for which `git credential` will obtain
99+
the login/password information (e.g. host, protocol, path), or to the
100+
actual credential data to be obtained (login/password).
101+
102+
The credential is split into a set of named attributes.
103+
Attributes are provided to the helper, one per line. Each attribute is
104+
specified by a key-value pair, separated by an `=` (equals) sign,
105+
followed by a newline. The key may contain any bytes except `=`,
106+
newline, or NUL. The value may contain any bytes except newline or NUL.
107+
In both cases, all bytes are treated as-is (i.e., there is no quoting,
108+
and one cannot transmit a value with newline or NUL in it). The list of
109+
attributes is terminated by a blank line or end-of-file.
110+
Git will send the following attributes (but may not send all of
111+
them for a given credential; for example, a `host` attribute makes no
112+
sense when dealing with a non-network protocol):
113+
114+
`protocol`::
115+
116+
The protocol over which the credential will be used (e.g.,
117+
`https`).
118+
119+
`host`::
120+
121+
The remote hostname for a network credential.
122+
123+
`path`::
124+
125+
The path with which the credential will be used. E.g., for
126+
accessing a remote https repository, this will be the
127+
repository's path on the server.
128+
129+
`username`::
130+
131+
The credential's username, if we already have one (e.g., from a
132+
URL, from the user, or from a previously run helper).
133+
134+
`password`::
135+
136+
The credential's password, if we are asking it to be stored.

Documentation/technical/api-credentials.txt

Lines changed: 3 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -241,42 +241,9 @@ appended to its command line, which is one of:
241241
Remove a matching credential, if any, from the helper's storage.
242242

243243
The details of the credential will be provided on the helper's stdin
244-
stream. The credential is split into a set of named attributes.
245-
Attributes are provided to the helper, one per line. Each attribute is
246-
specified by a key-value pair, separated by an `=` (equals) sign,
247-
followed by a newline. The key may contain any bytes except `=`,
248-
newline, or NUL. The value may contain any bytes except newline or NUL.
249-
In both cases, all bytes are treated as-is (i.e., there is no quoting,
250-
and one cannot transmit a value with newline or NUL in it). The list of
251-
attributes is terminated by a blank line or end-of-file.
252-
253-
Git will send the following attributes (but may not send all of
254-
them for a given credential; for example, a `host` attribute makes no
255-
sense when dealing with a non-network protocol):
256-
257-
`protocol`::
258-
259-
The protocol over which the credential will be used (e.g.,
260-
`https`).
261-
262-
`host`::
263-
264-
The remote hostname for a network credential.
265-
266-
`path`::
267-
268-
The path with which the credential will be used. E.g., for
269-
accessing a remote https repository, this will be the
270-
repository's path on the server.
271-
272-
`username`::
273-
274-
The credential's username, if we already have one (e.g., from a
275-
URL, from the user, or from a previously run helper).
276-
277-
`password`::
278-
279-
The credential's password, if we are asking it to be stored.
244+
stream. The exact format is the same as the input/output format of the
245+
`git credential` plumbing command (see the section `INPUT/OUTPUT
246+
FORMAT` in linkgit:git-credential[7] for a detailed specification).
280247

281248
For a `get` operation, the helper should produce a list of attributes
282249
on stdout in the same format. A helper is free to produce a subset, or

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -487,7 +487,6 @@ X =
487487
PROGRAMS += $(patsubst %.o,git-%$X,$(PROGRAM_OBJS))
488488

489489
TEST_PROGRAMS_NEED_X += test-chmtime
490-
TEST_PROGRAMS_NEED_X += test-credential
491490
TEST_PROGRAMS_NEED_X += test-ctype
492491
TEST_PROGRAMS_NEED_X += test-date
493492
TEST_PROGRAMS_NEED_X += test-delta
@@ -835,6 +834,7 @@ BUILTIN_OBJS += builtin/commit-tree.o
835834
BUILTIN_OBJS += builtin/commit.o
836835
BUILTIN_OBJS += builtin/config.o
837836
BUILTIN_OBJS += builtin/count-objects.o
837+
BUILTIN_OBJS += builtin/credential.o
838838
BUILTIN_OBJS += builtin/describe.o
839839
BUILTIN_OBJS += builtin/diff-files.o
840840
BUILTIN_OBJS += builtin/diff-index.o

builtin.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ extern int cmd_commit(int argc, const char **argv, const char *prefix);
6565
extern int cmd_commit_tree(int argc, const char **argv, const char *prefix);
6666
extern int cmd_config(int argc, const char **argv, const char *prefix);
6767
extern int cmd_count_objects(int argc, const char **argv, const char *prefix);
68+
extern int cmd_credential(int argc, const char **argv, const char *prefix);
6869
extern int cmd_describe(int argc, const char **argv, const char *prefix);
6970
extern int cmd_diff_files(int argc, const char **argv, const char *prefix);
7071
extern int cmd_diff_index(int argc, const char **argv, const char *prefix);
Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,18 @@
1-
#include "cache.h"
1+
#include "git-compat-util.h"
22
#include "credential.h"
3-
#include "string-list.h"
3+
#include "builtin.h"
44

55
static const char usage_msg[] =
6-
"test-credential <fill|approve|reject> [helper...]";
6+
"git credential [fill|approve|reject]";
77

8-
int main(int argc, const char **argv)
8+
int cmd_credential(int argc, const char **argv, const char *prefix)
99
{
1010
const char *op;
1111
struct credential c = CREDENTIAL_INIT;
12-
int i;
1312

1413
op = argv[1];
1514
if (!op)
1615
usage(usage_msg);
17-
for (i = 2; i < argc; i++)
18-
string_list_append(&c.helpers, argv[i]);
1916

2017
if (credential_read(&c, stdin) < 0)
2118
die("unable to read credential from stdin");
@@ -26,13 +23,12 @@ int main(int argc, const char **argv)
2623
printf("username=%s\n", c.username);
2724
if (c.password)
2825
printf("password=%s\n", c.password);
29-
}
30-
else if (!strcmp(op, "approve"))
26+
} else if (!strcmp(op, "approve")) {
3127
credential_approve(&c);
32-
else if (!strcmp(op, "reject"))
28+
} else if (!strcmp(op, "reject")) {
3329
credential_reject(&c);
34-
else
30+
} else {
3531
usage(usage_msg);
36-
32+
}
3733
return 0;
3834
}

git.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,7 @@ static void handle_internal_command(int argc, const char **argv)
351351
{ "commit-tree", cmd_commit_tree, RUN_SETUP },
352352
{ "config", cmd_config, RUN_SETUP_GENTLY },
353353
{ "count-objects", cmd_count_objects, RUN_SETUP },
354+
{ "credential", cmd_credential, RUN_SETUP_GENTLY },
354355
{ "describe", cmd_describe, RUN_SETUP },
355356
{ "diff", cmd_diff },
356357
{ "diff-files", cmd_diff_files, RUN_SETUP | NEED_WORK_TREE },

t/lib-credential.sh

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,20 @@
44
# stdout and stderr should be provided on stdin,
55
# separated by "--".
66
check() {
7+
credential_opts=
8+
credential_cmd=$1
9+
shift
10+
for arg in "$@"; do
11+
credential_opts="$credential_opts -c credential.helper='$arg'"
12+
done
713
read_chunk >stdin &&
814
read_chunk >expect-stdout &&
915
read_chunk >expect-stderr &&
10-
test-credential "$@" <stdin >stdout 2>stderr &&
16+
if ! eval "git $credential_opts credential $credential_cmd <stdin >stdout 2>stderr"; then
17+
echo "git credential failed with code $?" &&
18+
cat stderr &&
19+
false
20+
fi &&
1121
test_cmp expect-stdout stdout &&
1222
test_cmp expect-stderr stderr
1323
}
@@ -41,7 +51,7 @@ reject() {
4151
echo protocol=$2
4252
echo host=$3
4353
echo username=$4
44-
) | test-credential reject $1
54+
) | git -c credential.helper=$1 credential reject
4555
}
4656

4757
helper_test() {

0 commit comments

Comments
 (0)