mirror of
https://gitea.com/gitea/tea.git
synced 2026-10-26 19:11:25 +01:00
fix(auth): reset other credential helpers in auth setup-git
setup-git appended tea's helper after the helpers Git already had, such as osxkeychain from the system configuration. Those helpers answered first, and after a push Git asked every helper to store tea's token, so it ended up in the macOS Keychain where auth logout never removes it. setup-git now writes an empty helper for the instance before tea's own, as tea already does for its per-operation Git credentials. Add --keep-helpers for the previous behavior. Signed-off-by: bircni <bircni@icloud.com>
This commit is contained in:
3 files changed
+57
-7
No files matched your search
@@ -106,7 +106,7 @@ func (a *application) gitCredentialCommand() *cobra.Command {
|
||||
}
|
||||
|
||||
func (a *application) setupGitCommand() *cobra.Command {
|
||||
var local bool
|
||||
var local, keepHelpers bool
|
||||
command := &cobra.Command{Use: "setup-git", Short: "Explicitly register tea as a scoped Git credential helper", Annotations: textOutput("setup-git configures Git"), Args: argsExact(0), RunE: func(cmd *cobra.Command, _ []string) error {
|
||||
target, err := a.resolveTarget(cmd.Context(), false, false)
|
||||
if err != nil {
|
||||
@@ -117,9 +117,10 @@ func (a *application) setupGitCommand() *cobra.Command {
|
||||
return err
|
||||
}
|
||||
pinned, _ := a.selectedUser()
|
||||
return git.SetupCredentials(cmd.Context(), a.deps.Git, git.CredentialSetup{Directory: a.options.cwd, Local: local, Instance: target.Host, Executable: executable, User: pinned, ConfigDirectory: configDir})
|
||||
return git.SetupCredentials(cmd.Context(), a.deps.Git, git.CredentialSetup{Directory: a.options.cwd, Local: local, KeepHelpers: keepHelpers, Instance: target.Host, Executable: executable, User: pinned, ConfigDirectory: configDir})
|
||||
}}
|
||||
command.Flags().BoolVar(&local, "local", false, "Configure only the current Git repository instead of global Git configuration")
|
||||
command.Flags().BoolVar(&keepHelpers, "keep-helpers", false, "Keep other credential helpers for the instance; they are asked first and store tea's token")
|
||||
return command
|
||||
}
|
||||
|
||||
|
||||
@@ -57,9 +57,12 @@ func CredentialArguments(instance, executable, user, configDir string) ([]string
|
||||
type CredentialSetup struct {
|
||||
Directory, Instance, Executable, User, ConfigDirectory string
|
||||
Local bool
|
||||
// KeepHelpers adds tea's helper after other helpers instead of resetting them for the instance.
|
||||
KeepHelpers bool
|
||||
}
|
||||
|
||||
// SetupCredentials adds a scoped helper without removing other credential helpers.
|
||||
// SetupCredentials installs a helper scoped to the instance. Unless KeepHelpers is set, an empty
|
||||
// helper first resets other helpers for the instance, so they neither answer for tea nor store its token.
|
||||
func SetupCredentials(ctx context.Context, runner Runner, options CredentialSetup) error {
|
||||
normalized, err := settings.NormalizeHost(options.Instance)
|
||||
if err != nil {
|
||||
@@ -100,8 +103,17 @@ func SetupCredentials(ctx context.Context, runner Runner, options CredentialSetu
|
||||
return err
|
||||
}
|
||||
}
|
||||
if slices.Contains(helpers, helper) {
|
||||
return nil
|
||||
if options.KeepHelpers {
|
||||
if slices.Contains(helpers, helper) {
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
if slices.Equal(helpers, []string{"", helper}) {
|
||||
return nil
|
||||
}
|
||||
if _, err := runner.Output(ctx, cwd, false, "config", scope, "--replace-all", prefix+"helper", ""); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
_, err = runner.Output(ctx, cwd, false, "config", scope, "--add", prefix+"helper", helper)
|
||||
return err
|
||||
|
||||
@@ -26,8 +26,9 @@ func TestSetupGitCredentialsPreservesHelpersAndIsIdempotent(t *testing.T) {
|
||||
_, err = runner.Output(ctx, cwd, false, "config", "--local", "--add", key, "existing-helper")
|
||||
require.NoError(t, err)
|
||||
executable := filepath.Join(cwd, "path with spaces and 'quote'", "tea")
|
||||
require.NoError(t, SetupCredentials(ctx, runner, CredentialSetup{Directory: cwd, Local: true, Instance: instance, Executable: executable, User: "alice"}))
|
||||
require.NoError(t, SetupCredentials(ctx, runner, CredentialSetup{Directory: cwd, Local: true, Instance: instance, Executable: executable, User: "alice"}))
|
||||
setup := CredentialSetup{Directory: cwd, Local: true, KeepHelpers: true, Instance: instance, Executable: executable, User: "alice"}
|
||||
require.NoError(t, SetupCredentials(ctx, runner, setup))
|
||||
require.NoError(t, SetupCredentials(ctx, runner, setup))
|
||||
data, err := runner.Output(ctx, cwd, false, "config", "--local", "--get-all", key)
|
||||
require.NoError(t, err)
|
||||
helpers := strings.Split(data, "\n")
|
||||
@@ -41,6 +42,42 @@ func TestSetupGitCredentialsPreservesHelpersAndIsIdempotent(t *testing.T) {
|
||||
require.Equal(t, "true", data)
|
||||
}
|
||||
|
||||
func TestSetupGitCredentialsResetsOtherHelpersForTheInstance(t *testing.T) {
|
||||
if _, err := exec.LookPath("git"); err != nil {
|
||||
t.Skip("Git is not installed")
|
||||
}
|
||||
t.Setenv("GIT_CONFIG_NOSYSTEM", "1")
|
||||
t.Setenv("GIT_CONFIG_GLOBAL", filepath.Join(t.TempDir(), "gitconfig"))
|
||||
t.Setenv("GIT_TERMINAL_PROMPT", "0")
|
||||
ctx := context.Background()
|
||||
cwd := t.TempDir()
|
||||
runner := System{}
|
||||
_, err := runner.Output(ctx, cwd, false, "init")
|
||||
require.NoError(t, err)
|
||||
instance := "https://example.test:8443/gitea"
|
||||
key := "credential." + instance + ".helper"
|
||||
for _, helper := range [][2]string{{"credential.helper", `!f() { test "$1" = get && printf 'username=other\npassword=leaked\n'; }; f`}, {key, "stale-helper"}} {
|
||||
_, err = runner.Output(ctx, cwd, false, "config", "--local", "--add", helper[0], helper[1])
|
||||
require.NoError(t, err)
|
||||
}
|
||||
executable := filepath.Join(t.TempDir(), "tea")
|
||||
require.NoError(t, os.WriteFile(executable, []byte("#!/bin/sh\nfor last; do :; done\nif [ \"$last\" = get ]; then printf 'username=tea\\npassword=tea-token\\n'; fi\n"), 0o755))
|
||||
setup := CredentialSetup{Directory: cwd, Local: true, Instance: instance, Executable: executable}
|
||||
require.NoError(t, SetupCredentials(ctx, runner, setup))
|
||||
require.NoError(t, SetupCredentials(ctx, runner, setup))
|
||||
helper, err := CredentialHelper(instance, executable, "", "")
|
||||
require.NoError(t, err)
|
||||
data, err := runner.Output(ctx, cwd, false, "config", "--local", "--null", "--get-all", key)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "\x00"+helper+"\x00", data)
|
||||
fill := exec.Command("git", "credential", "fill")
|
||||
fill.Dir = cwd
|
||||
fill.Stdin = strings.NewReader("protocol=https\nhost=example.test:8443\npath=gitea/alice/project.git\n\n")
|
||||
output, err := fill.Output()
|
||||
require.NoError(t, err)
|
||||
require.Contains(t, string(output), "username=tea\npassword=tea-token\n")
|
||||
}
|
||||
|
||||
func TestSetupGitCredentialsWorksWithoutAnExistingGlobalFile(t *testing.T) {
|
||||
home := t.TempDir()
|
||||
t.Setenv("GIT_CONFIG_GLOBAL", filepath.Join(home, "new.gitconfig"))
|
||||
|
||||
Reference in new issue
Block a user