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)
|
||||
}
|
||||
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"
|
||||
if auth.KeyFile != "" {
|
||||
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