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:
Lunny Xiao 2026-08-22 00:02:35 -07:00
parent ee531914cd
commit 9fd40479b7
3 changed files with 76 additions and 0 deletions

36
modules/git/auth_test.go Normal file
View 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)
}

View file

@ -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"

View 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))
}