Skip to content

Commit

Permalink
clone: auto-enable git-credential-store when necessary
Browse files Browse the repository at this point in the history
If the user clones with a URL containing a password and has no
credential helper configured, we're stuck. We don't want to write the
password into .git/config because that risks accidentally disclosing it.
But if we don't record it somewhere, subsequent fetches will fail unless
the user is there to input the password.

The best advice we can give the user is to set up a credential helper.
But we can actually go a step further and enable the "store" helper for
them. This still records the password in plaintext, but:

  1. It's not inside the repo directory, which makes it slightly less
     likely to be disclosed.

  2. The permissions on the storage file are tighter than what would be
     on .git/config.

So this is generally a security win over the old behavior of writing it
into .git/config. And it's a usability win over the more recent behavior
of just forgetting the password entirely.

The biggest downside is that it's a bit magical from the user's
perspective, because now the password is off in some other file (usually
~/.git-credentials, but sometimes in $XDG_CONFIG_HOME). Which
complicates things if they want to purge the repo and password, for
example, because now they can't just delete the repository directory.

The file location is documented, though, and we point people to the
documentation. So perhaps it will be enough (and better still, may lead
to them configuring a more secure helper).

Signed-off-by: Jeff King <[email protected]>
  • Loading branch information
peff committed Jan 9, 2025
1 parent acfda54 commit 0fac1e1
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 4 deletions.
19 changes: 16 additions & 3 deletions builtin/clone.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
#include "hook.h"
#include "bundle.h"
#include "bundle-uri.h"
#include "credential.h"

/*
* Overall FIXMEs:
Expand Down Expand Up @@ -963,8 +964,14 @@ static int path_exists(const char *path)
static const char sanitized_url_advice[] = N_(
"The URL you provided to Git contains a password. It will be\n"
"used to clone the repository, but to avoid accidental disclosure\n"
"the password will not be recorded. Further fetches from the remote\n"
"may require you to provide the password interactively.\n"
"the password will not be recorded in the repository config.\n"
"Since you have no credential helper configured, the \"store\" helper\n"
"has been enabled for this repository, and will provide the password\n"
"for further fetches.\n"
"\n"
"Note that the password is still stored in plaintext in the filesystem;\n"
"consider configuring a more secure helper. See \"git help gitcredentials\"\n"
"and \"git help git-credential-store\" for details.\n"
);

int cmd_clone(int argc,
Expand Down Expand Up @@ -1298,7 +1305,13 @@ int cmd_clone(int argc,

if (display_repo && strcmp(repo, display_repo)) {
warning(_("omitting password while storing URL in on-disk config"));
advise(_(sanitized_url_advice));
if (!url_has_credential_helper(display_repo)) {
strbuf_addf(&key, "credential.%s.helper",
display_repo);
git_config_set(key.buf, "store");
strbuf_reset(&key);
advise(_(sanitized_url_advice));
}
}
strbuf_addf(&key, "remote.%s.url", remote_name);
git_config_set(key.buf, display_repo ? display_repo : repo);
Expand Down
13 changes: 13 additions & 0 deletions credential.c
Original file line number Diff line number Diff line change
Expand Up @@ -695,3 +695,16 @@ void credential_from_url(struct credential *c, const char *url)
if (credential_from_url_gently(c, url, 0) < 0)
die(_("credential url cannot be parsed: %s"), url);
}

int url_has_credential_helper(const char *url)
{
struct credential c = CREDENTIAL_INIT;
int ret;

credential_from_url(&c, url);
credential_apply_config(&c);
ret = c.helpers.nr > 0;

credential_clear(&c);
return ret;
}
6 changes: 6 additions & 0 deletions credential.h
Original file line number Diff line number Diff line change
Expand Up @@ -301,4 +301,10 @@ int credential_from_url_gently(struct credential *, const char *url, int quiet);
int credential_match(const struct credential *want,
const struct credential *have, int match_password);

/*
* Return true if feeding "url" to the credential system would trigger one
* or more helpers.
*/
int url_has_credential_helper(const char *url);

#endif /* CREDENTIAL_H */
2 changes: 1 addition & 1 deletion t/t5550-http-fetch-dumb.sh
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ test_expect_success 'username is retained in URL, password is not' '
! grep pass url
'

test_expect_failure 'fetch of password-URL clone uses stored auth' '
test_expect_success 'fetch of password-URL clone uses stored auth' '
set_askpass wrong &&
git -C clone-auth-none fetch &&
expect_askpass none
Expand Down

0 comments on commit 0fac1e1

Please sign in to comment.