0
0
mirror of https://github.com/go-gitea/gitea.git synced 2026-06-22 12:15:19 +02:00

dedupe SSH agent setup, use ParseGitURL for IsSSHURL

This commit is contained in:
pomidorry 2026-05-17 20:22:48 +03:00
parent 1b48b9866f
commit b1069e7456
5 changed files with 47 additions and 89 deletions

View File

@ -72,3 +72,35 @@ func GetSSHKeypairForURL(ctx context.Context, repo *repo_model.Repository, url s
}
return GetSSHKeypairForRepository(ctx, repo)
}
// SetupMirrorSSHAgent prepares SSH key-based authentication for a mirror or
// migration git operation against remoteURL on behalf of repo. For non-SSH
// URLs (or when no keypair is available) it is a no-op. The returned cleanup
// is never nil and must always be called by the caller (typically via defer).
func SetupMirrorSSHAgent(ctx context.Context, repo *repo_model.Repository, remoteURL string) (sshAuthSock string, cleanup func(), err error) {
noop := func() {}
if !IsSSHURL(remoteURL) {
return "", noop, nil
}
keypair, err := GetSSHKeypairForRepository(ctx, repo)
if err != nil {
return "", noop, fmt.Errorf("failed to get SSH keypair for repository: %w", err)
}
if keypair == nil {
return "", noop, nil
}
privateKey, err := keypair.GetDecryptedPrivateKey()
if err != nil {
return "", noop, fmt.Errorf("failed to decrypt SSH private key: %w", err)
}
socketPath, agentCleanup, err := CreateTemporaryAgent(privateKey)
if err != nil {
return "", noop, fmt.Errorf("failed to create SSH agent: %w", err)
}
log.Debug("SSH agent ready for mirror %s (socket: %s)", repo.FullName(), socketPath)
return socketPath, agentCleanup, nil
}

View File

@ -23,7 +23,6 @@ import (
"code.gitea.io/gitea/modules/proxy"
repo_module "code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/setting"
ssh_module "code.gitea.io/gitea/modules/ssh"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/services/migrations"
@ -107,36 +106,6 @@ func checkRecoverableSyncError(stderrMessage string) bool {
}
// runSync returns true if sync finished without error.
// setupSSHAuth sets up SSH authentication for git operations if needed.
// It returns the SSH agent socket path, a cleanup function, and any error.
// If the URL is not SSH or no keypair is found, it returns empty string with a no-op cleanup.
func setupSSHAuth(ctx context.Context, repo *repo_model.Repository, remoteURL string) (string, func(), error) {
if !IsSSHURL(remoteURL) {
return "", func() {}, nil
}
keypair, err := GetSSHKeypairForURL(ctx, repo, remoteURL)
if err != nil {
return "", nil, fmt.Errorf("failed to get SSH keypair: %w", err)
}
if keypair == nil {
return "", func() {}, nil
}
privateKey, err := keypair.GetDecryptedPrivateKey()
if err != nil {
return "", nil, fmt.Errorf("failed to decrypt private key: %w", err)
}
socketPath, cleanup, err := ssh_module.CreateTemporaryAgent(privateKey)
if err != nil {
return "", nil, fmt.Errorf("failed to create SSH agent: %w", err)
}
log.Debug("SSH agent created for repository %s with socket: %s", repo.FullName(), socketPath)
return socketPath, cleanup, nil
}
func runSync(ctx context.Context, m *repo_model.Mirror) ([]*repo_module.SyncResult, bool) {
log.Trace("SyncMirrors [repo: %-v]: running git remote update...", m.Repo)
@ -149,7 +118,7 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*repo_module.SyncResu
timeout := time.Duration(setting.Git.Timeout.Mirror) * time.Second
// Setup SSH authentication if needed
sshAuthSock, cleanup, sshErr := setupSSHAuth(ctx, m.Repo, remoteURL.String())
sshAuthSock, cleanup, sshErr := SetupMirrorSSHAgent(ctx, m.Repo, remoteURL.String())
if sshErr != nil {
log.Error("SyncMirrors [repo: %-v]: SSH setup error %v", m.Repo, sshErr)
return nil, false

View File

@ -21,7 +21,6 @@ import (
"code.gitea.io/gitea/modules/proxy"
"code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/setting"
ssh_module "code.gitea.io/gitea/modules/ssh"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/services/migrations"
@ -168,36 +167,13 @@ func runPushSync(ctx context.Context, m *repo_model.PushMirror) error {
}
// Setup SSH authentication
if IsSSHURL(remoteURL.String()) {
if repo.Owner == nil {
if err := repo.LoadOwner(ctx); err != nil {
log.Error("Failed to load repository owner for %s: %v", repo.FullName(), err)
return util.SanitizeErrorCredentialURLs(err)
}
}
keypair, err := GetSSHKeypairForRepository(ctx, repo)
if err != nil {
log.Error("Failed to get SSH keypair for repository %s: %v", repo.FullName(), err)
return util.SanitizeErrorCredentialURLs(err)
}
if keypair != nil {
privateKey, err := keypair.GetDecryptedPrivateKey()
if err != nil {
log.Error("Failed to decrypt private key for repository %s: %v", repo.FullName(), err)
return util.SanitizeErrorCredentialURLs(err)
}
socketPath, cleanup, err := ssh_module.CreateTemporaryAgent(privateKey)
if err != nil {
log.Error("Failed to create SSH agent for repository %s: %v", repo.FullName(), err)
return util.SanitizeErrorCredentialURLs(err)
}
defer cleanup()
pushOpts.SSHAuthSock = socketPath
log.Debug("SSH agent created for push mirror %s with socket: %s", repo.FullName(), socketPath)
}
sshAuthSock, cleanup, err := SetupMirrorSSHAgent(ctx, repo, remoteURL.String())
if err != nil {
log.Error("Failed to set up SSH agent for push mirror %s: %v", repo.FullName(), err)
return util.SanitizeErrorCredentialURLs(err)
}
defer cleanup()
pushOpts.SSHAuthSock = sshAuthSock
if err := gitrepo.PushToExternal(ctx, storageRepo, pushOpts); err != nil {
log.Error("Error pushing %s mirror[%d] remote %s: %v", storageRepo.RelativePath(), m.ID, m.RemoteName, err)

View File

@ -50,3 +50,10 @@ func IsSSHURL(url string) bool {
func GetSSHKeypairForURL(ctx context.Context, repo *repo_model.Repository, url string) (*repo_model.UserSSHKeypair, error) {
return ssh_module.GetSSHKeypairForURL(ctx, repo, url)
}
// SetupMirrorSSHAgent prepares SSH key-based authentication for a mirror or
// migration git operation against url on behalf of repo. The returned cleanup
// is never nil and must always be called by the caller (typically via defer).
func SetupMirrorSSHAgent(ctx context.Context, repo *repo_model.Repository, url string) (string, func(), error) {
return ssh_module.SetupMirrorSSHAgent(ctx, repo, url)
}

View File

@ -28,34 +28,8 @@ import (
"code.gitea.io/gitea/modules/util"
)
func setupMigrationSSHAuth(ctx context.Context, repo *repo_model.Repository, remoteURL string) (string, func(), error) {
if !ssh_module.IsSSHURL(remoteURL) {
return "", func() {}, nil
}
keypair, err := ssh_module.GetSSHKeypairForRepository(ctx, repo)
if err != nil {
return "", nil, fmt.Errorf("failed to get SSH keypair for repository: %w", err)
}
if keypair == nil {
return "", func() {}, nil
}
privateKey, err := keypair.GetDecryptedPrivateKey()
if err != nil {
return "", nil, fmt.Errorf("failed to decrypt private key: %w", err)
}
socketPath, cleanup, err := ssh_module.CreateTemporaryAgent(privateKey)
if err != nil {
return "", nil, fmt.Errorf("failed to create SSH agent: %w", err)
}
return socketPath, cleanup, nil
}
func cloneExternalRepoWithSSHAuth(ctx context.Context, repo *repo_model.Repository, remoteURL string, storageRepo gitrepo.Repository, cloneOpts git.CloneRepoOptions) error {
sshAuthSock, cleanup, err := setupMigrationSSHAuth(ctx, repo, remoteURL)
sshAuthSock, cleanup, err := ssh_module.SetupMirrorSSHAgent(ctx, repo, remoteURL)
if err != nil {
return err
}