cli/pkg/cmd/auth/shared/git_credential.go
Kynan Ware 65fcba95d9 Add godoc comments to exported symbols in pkg/cmd/auth
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-04 16:08:04 -07:00

95 lines
3.6 KiB
Go

package shared
import (
"errors"
"github.com/cli/cli/v2/git"
"github.com/cli/cli/v2/pkg/cmd/auth/shared/gitcredentials"
)
// HelperConfig defines an interface for configuring and querying git credential helpers.
type HelperConfig interface {
ConfigureOurs(hostname string) error
ConfiguredHelper(hostname string) (gitcredentials.Helper, error)
}
// GitCredentialFlow manages the interactive flow for configuring git credential helpers during authentication.
type GitCredentialFlow struct {
Prompter Prompt
HelperConfig HelperConfig
Updater *gitcredentials.Updater
shouldSetup bool
helper gitcredentials.Helper
scopes []string
}
// Prompt asks the user whether to configure git credentials for the given hostname.
func (flow *GitCredentialFlow) Prompt(hostname string) error {
// First we'll fetch the credential helper that would be used for this host
var configuredHelperErr error
flow.helper, configuredHelperErr = flow.HelperConfig.ConfiguredHelper(hostname)
// If the helper is gh itself, then we don't need to ask the user if they want to update their git credentials
// because it will happen automatically by virtue of the fact that gh will return the active token.
//
// Since gh is the helper, this token may be used for git operations, so we'll additionally request the workflow
// scope to ensure that git push operations that include workflow changes succeed.
if flow.helper.IsOurs() {
flow.scopes = append(flow.scopes, "workflow")
return nil
}
// Prompt the user for whether they want to configure git with the newly obtained token
result, err := flow.Prompter.Confirm("Authenticate Git with your GitHub credentials?", true)
if err != nil {
return err
}
flow.shouldSetup = result
if flow.shouldSetup {
// If the user does want to configure git, we'll check the error returned from fetching the configured helper
// above. If the error indicates that git isn't installed, we'll return an error now to ensure that the auth
// flow is aborted before the user goes any further.
//
// Note that this is _slightly_ naive because there may be other reasons that fetching the configured helper
// fails that might cause later failures but this code has existed for a long time and I don't want to change
// it as part of a refactoring.
//
// Refs:
// * https://git-scm.com/docs/git-config#_description
// * https://github.com/cli/cli/pull/4109
var errNotInstalled *git.NotInstalled
if errors.As(configuredHelperErr, &errNotInstalled) {
return configuredHelperErr
}
// On the other hand, if the user has requested setup we'll additionally request the workflow
// scope to ensure that git push operations that include workflow changes succeed.
flow.scopes = append(flow.scopes, "workflow")
}
return nil
}
// Scopes returns the additional OAuth scopes required by the credential flow.
func (flow *GitCredentialFlow) Scopes() []string {
return flow.scopes
}
// ShouldSetup reports whether the user opted to configure git credentials.
func (flow *GitCredentialFlow) ShouldSetup() bool {
return flow.shouldSetup
}
// Setup configures git credential storage for the given hostname, username, and token.
func (flow *GitCredentialFlow) Setup(hostname, username, authToken string) error {
// If there is no credential helper configured then we will set ourselves up as
// the credential helper for this host.
if !flow.helper.IsConfigured() {
return flow.HelperConfig.ConfigureOurs(hostname)
}
// Otherwise, we'll tell git to inform the existing credential helper of the new credentials.
return flow.Updater.Update(hostname, username, authToken)
}