-
Notifications
You must be signed in to change notification settings - Fork 2.1k
lfsapi: don't query askpass for given creds #3126
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking great so far, thanks for tackling this one!
lfsapi/creds.go
Outdated
func (a *AskPassCredentialHelper) Fill(what Creds) (Creds, error) { | ||
var user bytes.Buffer | ||
var pass bytes.Buffer | ||
var err bytes.Buffer | ||
|
||
var username string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, my reading of this code indicates that username
and password
are used to hold the final values of user
and pass
when we defer to the GIT_ASKPASS or core.askpass program.
It took me a couple of reads to determine the difference between user
and username
. I think there are a couple of ways that it could be clarified:
-
Document the difference between the two above in a comment.
-
Move the
user
,pass
, anderr
variables to the else block in L109. -
Replace all three with:
var (
user strings.Builder
pass strings.Builder
)
and then write appropriately into both.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like option 3, since we'll only have one variable for each string. I'll go ahead and update this
lfsapi/creds.go
Outdated
} else { | ||
// 'ucmd' will run the GIT_ASKPASS (or core.askpass) command prompting | ||
// for a username. | ||
ucmd := exec.Command(a.Program, a.args(fmt.Sprintf("Username for %q", u))...) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another option is that we could extract this entire block into another function and call that. What do you think of the signature:
func fillFromProgram(what Creds) error {
var (
user bytes.Buffer
err bytes.Buffer
)
cmd := exec.Command(a.Program, a.args(fmt.Sprintf("Username for %q", u))...)
cmd.Stderr = &err
cmd.Stdout = &user
if err := cmd.Run(); err != nil {
return err
}
if err.Len() > 0 {
return errors.New(err.String())
}
what["username"] = user.String()
// etc ...
return nil
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that's a great idea! I think though I'd prefer if the function we extract returns a string, and the Fill()
function can handle adding that to the credential as necessary. I think it'll be a little cleaner, and we don't need to worry about the fact that Username
has different capitalization with the command and the credentials map.
git commit -m "initial commit" | ||
|
||
# $password is defined from test/cmd/lfstest-gitserver.go (see: skipIfBadAuth) | ||
export LFS_ASKPASS_USERNAME="fakeuser" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sanity checking for myself, this export
should be OK since it's run in a sub-shell (and therefore won't leak into the environment).
test/test-askpass.sh
Outdated
# $password is defined from test/cmd/lfstest-gitserver.go (see: skipIfBadAuth) | ||
export LFS_ASKPASS_USERNAME="fakeuser" | ||
export LFS_ASKPASS_PASSWORD="fakepass" | ||
git config "credential.helper" "" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's make sure that this is repository-local with the --local
flag.
test/test-askpass.sh
Outdated
|
||
GIT_ASKPASS="lfs-askpass" SSH_ASKPASS="dont-call-me" GIT_TRACE=1 GIT_CURL_VERBOSE=1 git push origin master 2>&1 | tee push.log | ||
|
||
GITSERVER_USER="$(printf $GITSERVER | sed -e 's/http:\/\//http:\/\/user@/')" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm... is there a way that we could move some of this into a function and not duplicate it in the above? I'm not sure if it makes sense to do that, but perhaps we should give it a shot so that this sed
invocation isn't duplicated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some of this (including GITSERVER_USER
) isn't actually being used in the test, so it may just be best to remove it
@ttaylorr Thanks for the review! I've gone ahead and addressed your feedback |
lfsapi/creds.go
Outdated
|
||
// 'ucmd' will run the GIT_ASKPASS (or core.askpass) command prompting | ||
// for the desired valueType (`Username` or `Password`) | ||
ucmd := exec.Command(a.Program, a.args(fmt.Sprintf("%s for %q", valueType, u))...) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: do we want to call this cmd
instead of ucmd
? My impression is that ucmd
is a relic of when we had separate exec.Command()
invocations to capture usernames and passwords.
lfsapi/creds.go
Outdated
|
||
// 'ucmd' will run the GIT_ASKPASS (or core.askpass) command prompting | ||
// for the desired valueType (`Username` or `Password`) | ||
ucmd := exec.Command(a.Program, a.args(fmt.Sprintf("%s for %q", valueType, u))...) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line looks good otherwise. A gentle suggestion would be that we switch valueType
to make sure that it's one of the valid things we allow (i.e., Username or Password). Alternatively, we could even extract a type, like:
type credValueType int
const (
credValueTypeUnknown credValueType = iota
credValueTypeUsername
credValueTypePassword
)
lfsapi/creds.go
Outdated
creds := make(Creds) | ||
creds["username"] = username | ||
creds["password"] = strings.TrimSpace(password) | ||
creds["username"] = strings.TrimSpace(creds["username"]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think these final strings.TrimSpace
calls are unnecessary, since the body of getFromProgram
calls strings.TrimFromSpace(and its an invariant that
what` will have space-less values, too).
lfsapi/creds.go
Outdated
u := &url.URL{ | ||
Scheme: what["protocol"], | ||
Host: what["host"], | ||
Path: what["path"], | ||
} | ||
|
||
creds := make(Creds) | ||
|
||
if givenUser, ok := what["username"]; ok { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This pattern roughly breaks down for me as:
- See if
what
has a given key, ex. "username". - If so, copy it to
creds
. - If not, invoke
getFromProgram
with some mapping ofusername
->Username
. - If the above is OK, copy that into
creds
. - If not, report an error.
If this is the same for username
and password
, could we extract another function that captures the above flow?
When creds have already been provided to git (i.e. through a git URL), use those instead of querying the askpass program
Extract askpass querying into its own separate function
Cleanup the `provided credentials` askpass test by removing unused/unneeded environment variables. Also, ensure config changes are local to the repository.
Add a new `getValue` askpass function that returns the value of a particular credential type by returning the existing value if that credential has already been provided, or by querying the askpass program if that credential has not yet been provided.
ce23689
to
76ccd68
Compare
@ttaylorr Thanks for the review! I've just pushed up a new commit to address your feedback, and have also rebased this PR onto master |
@ttaylorr Thanks for the review! I've just pushed up a new commit to
address your feedback, and have also rebased this PR onto master
Thanks for taking my feedback :-). This looks to be in good shape to me,
so I've merged it into master while you're on vacation.
|
When creds have already been provided to git (i.e. through a
git URL), use those instead of querying the askpass program
Closes #2894