mirror of
https://gitea.com/gitea/tea.git
synced 2026-10-26 19:11:25 +01:00
138 lines
6.3 KiB
Go
138 lines
6.3 KiB
Go
// Copyright 2026 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package git
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/kballard/go-shellquote"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestSetupGitCredentialsPreservesHelpersAndIsIdempotent(t *testing.T) {
|
|
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"
|
|
_, 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")
|
|
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")
|
|
require.Len(t, helpers, 2)
|
|
require.Equal(t, "existing-helper", helpers[0])
|
|
words, err := shellquote.Split(strings.TrimPrefix(helpers[1], "!"))
|
|
require.NoError(t, err)
|
|
require.Equal(t, []string{executable, "auth", "git-credential", "--host", instance, "--user", "alice"}, words)
|
|
data, err = runner.Output(ctx, cwd, false, "config", "--local", "--get", "credential."+instance+".useHttpPath")
|
|
require.NoError(t, err)
|
|
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"))
|
|
executable, err := os.Executable()
|
|
require.NoError(t, err)
|
|
require.NoError(t, SetupCredentials(context.Background(), System{}, CredentialSetup{Directory: home, Instance: "https://example.test", Executable: executable}))
|
|
data, err := os.ReadFile(filepath.Join(home, "new.gitconfig"))
|
|
require.NoError(t, err)
|
|
require.Contains(t, string(data), "useHttpPath = true")
|
|
require.Contains(t, string(data), "auth git-credential")
|
|
}
|
|
|
|
func TestRejectCredentialsAsksHelpersToEraseTheAccount(t *testing.T) {
|
|
if _, err := exec.LookPath("git"); err != nil {
|
|
t.Skip("Git is not installed")
|
|
}
|
|
t.Setenv("GIT_CONFIG_NOSYSTEM", "1")
|
|
home := t.TempDir()
|
|
log := filepath.Join(home, "helper.log")
|
|
t.Setenv("GIT_CONFIG_GLOBAL", filepath.Join(home, "gitconfig"))
|
|
ctx := context.Background()
|
|
runner := System{}
|
|
_, err := runner.Output(ctx, home, false, "config", "--global", "credential.helper", "!f() { echo \"op=$1\" >> '"+log+"'; cat >> '"+log+"'; }; f")
|
|
require.NoError(t, err)
|
|
store := filepath.Join(home, "git-credentials")
|
|
_, err = runner.Output(ctx, home, false, "config", "--global", "--add", "credential.helper", "store --file="+store)
|
|
require.NoError(t, err)
|
|
own := "http://alice:own-password@localhost:3001\n"
|
|
require.NoError(t, os.WriteFile(store, []byte(own+"http://alice:tea-token@localhost:3001/gitea/alice/project.git\n"), 0o600))
|
|
require.Empty(t, HelperScope(ctx, runner, home, "http://localhost:3001"))
|
|
require.NoError(t, RejectCredentials(ctx, runner, home, "http://localhost:3001/gitea", "alice", "tea-token"))
|
|
data, err := os.ReadFile(log)
|
|
require.NoError(t, err)
|
|
require.Equal(t, "op=erase\nprotocol=http\nhost=localhost:3001\nusername=alice\npassword=tea-token\n", string(data))
|
|
data, err = os.ReadFile(store)
|
|
require.NoError(t, err)
|
|
require.Equal(t, own, string(data), "only the copy of tea's token is erased")
|
|
require.NoError(t, RejectCredentials(ctx, runner, home, "http://localhost:3001", "alice", ""))
|
|
data, err = os.ReadFile(store)
|
|
require.NoError(t, err)
|
|
require.Equal(t, own, string(data), "without a token nothing is erased")
|
|
executable, err := os.Executable()
|
|
require.NoError(t, err)
|
|
require.NoError(t, SetupCredentials(ctx, runner, CredentialSetup{Directory: home, Instance: "http://localhost:3001", Executable: executable}))
|
|
require.Equal(t, "global", HelperScope(ctx, runner, home, "http://localhost:3001"))
|
|
require.Empty(t, HelperScope(ctx, runner, home, "http://localhost:3002"))
|
|
}
|
|
|
|
func TestGitMissingConfigValueCarriesExitCode(t *testing.T) {
|
|
if _, err := exec.LookPath("git"); err != nil {
|
|
t.Skip("Git is not installed")
|
|
}
|
|
_, err := (System{}).Output(context.Background(), t.TempDir(), false, "config", "--file", filepath.Join(t.TempDir(), "missing"), "--get", "not.present")
|
|
var failure *CommandError
|
|
require.ErrorAs(t, err, &failure)
|
|
require.Equal(t, 1, failure.ExitCode)
|
|
}
|