mirror of
https://gitea.com/gitea/tea.git
synced 2026-09-10 07:26:33 -04:00
fix(git): preserve user SSH command for native git operations
tea previously set GIT_SSH_COMMAND=ssh for every SSH operation, even when it had no identity or passphrase to inject. Let git fall back to its own SSH command in that case so core.sshCommand, GIT_SSH_COMMAND, and the normal OpenSSH known_hosts handling are respected. Add regression coverage for ed25519 key parsing and CLI SSH auth setup. Signed-off-by: Lunny Xiao <xiaolunwen@gmail.com>
This commit is contained in:
parent
ee531914cd
commit
9fd40479b7
36
modules/git/auth_test.go
Normal file
36
modules/git/auth_test.go
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
// Copyright 2026 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package git
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/ed25519"
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/pem"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"golang.org/x/crypto/ssh"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGetAuthForURLSupportsEd25519PrivateKey(t *testing.T) {
|
||||||
|
_, privateKey, err := ed25519.GenerateKey(rand.Reader)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
block, err := ssh.MarshalPrivateKey(privateKey, "")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
keyFile := filepath.Join(t.TempDir(), "id_ed25519")
|
||||||
|
require.NoError(t, os.WriteFile(keyFile, pem.EncodeToMemory(block), 0o600))
|
||||||
|
|
||||||
|
remoteURL, err := url.Parse("ssh://git@example.com/owner/repo")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
auth, err := GetAuthForURL(remoteURL, "", keyFile, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, "ssh", auth.Scheme)
|
||||||
|
require.Equal(t, keyFile, auth.KeyFile)
|
||||||
|
}
|
||||||
|
|
@ -306,6 +306,13 @@ func prepareCLIAuth(auth *AuthMethod) ([]string, []string, func(), error) {
|
||||||
configs = append(configs, "http.extraHeader="+header)
|
configs = append(configs, "http.extraHeader="+header)
|
||||||
}
|
}
|
||||||
case "ssh":
|
case "ssh":
|
||||||
|
// Let git use its default SSH command when tea does not need to inject
|
||||||
|
// an identity or passphrase. Overriding it unconditionally would bypass
|
||||||
|
// the user's core.sshCommand and GIT_SSH_COMMAND settings, including any
|
||||||
|
// host-key/known_hosts handling configured there.
|
||||||
|
if auth.KeyFile == "" && auth.KeyPassphrase == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
sshCommand := "ssh"
|
sshCommand := "ssh"
|
||||||
if auth.KeyFile != "" {
|
if auth.KeyFile != "" {
|
||||||
sshCommand += " -i " + shellQuote(auth.KeyFile) + " -o IdentitiesOnly=yes"
|
sshCommand += " -i " + shellQuote(auth.KeyFile) + " -o IdentitiesOnly=yes"
|
||||||
|
|
|
||||||
33
modules/git/cli_backend_test.go
Normal file
33
modules/git/cli_backend_test.go
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
// Copyright 2026 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package git
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPrepareCLIAuthSSHUsesGitDefaultCommandWithoutKey(t *testing.T) {
|
||||||
|
configs, env, cleanup, err := prepareCLIAuth(&AuthMethod{Scheme: "ssh", Username: "git"})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Empty(t, configs)
|
||||||
|
require.Empty(t, env)
|
||||||
|
require.NotNil(t, cleanup)
|
||||||
|
cleanup()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPrepareCLIAuthSSHInjectsConfiguredKey(t *testing.T) {
|
||||||
|
keyFile := "/tmp/tea test key"
|
||||||
|
configs, env, cleanup, err := prepareCLIAuth(&AuthMethod{Scheme: "ssh", KeyFile: keyFile})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Empty(t, configs)
|
||||||
|
require.NotNil(t, cleanup)
|
||||||
|
cleanup()
|
||||||
|
|
||||||
|
require.Len(t, env, 1)
|
||||||
|
require.Contains(t, env[0], "GIT_SSH_COMMAND=ssh ")
|
||||||
|
require.Contains(t, env[0], "IdentitiesOnly=yes")
|
||||||
|
require.Contains(t, env[0], shellQuote(keyFile))
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue