From fc4d490b357b5bed49b14c41123bc5887ad1f315 Mon Sep 17 00:00:00 2001 From: silverwind Date: Sat, 31 Oct 2026 16:24:13 +0100 Subject: [PATCH] fix(ssh): let pushes finish when the client disconnects early (#40105) With the built-in SSH server, closing the client connection cancelled the `gitea serv` process tree. go-git based clients close it right after the push report, so post-receive was killed and branches, pull requests, webhooks and Actions were not updated. The command now runs under the server's hammer context like with OpenSSH, where it ends once its pipes close or at shutdown. --- modules/ssh/server.go | 12 ++++-------- modules/ssh/ssh.go | 5 +---- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/modules/ssh/server.go b/modules/ssh/server.go index 3213e1c46ec..d1c95bc914b 100644 --- a/modules/ssh/server.go +++ b/modules/ssh/server.go @@ -28,7 +28,6 @@ type sshServer struct { type sshSession struct { gossh.Channel conn *gossh.ServerConn - ctx context.Context rawCmd string env []string } @@ -86,10 +85,7 @@ func (srv *sshServer) serve(listener net.Listener) error { func (srv *sshServer) handleConn(netConn net.Conn) { defer netConn.Close() - ctx, cancel := context.WithCancel(graceful.GetManager().HammerContext()) - defer cancel() - - sshConn, sshChannels, sshReqs, err := gossh.NewServerConn(netConn, srv.newServerConfig(ctx)) + sshConn, sshChannels, sshReqs, err := gossh.NewServerConn(netConn, srv.newServerConfig(graceful.GetManager().HammerContext())) if err != nil { // OpenSSH's logs are something like: // * disconnect without sending anything: "Connection closed by 1.2.3.4 port 5678" @@ -107,11 +103,11 @@ func (srv *sshServer) handleConn(netConn net.Conn) { _ = newChan.Reject(gossh.UnknownChannelType, "unsupported channel type") continue } - go handleSessionChannel(ctx, sshConn, newChan) + go handleSessionChannel(sshConn, newChan) } } -func handleSessionChannel(ctx context.Context, conn *gossh.ServerConn, newChan gossh.NewChannel) { +func handleSessionChannel(conn *gossh.ServerConn, newChan gossh.NewChannel) { channel, reqs, err := newChan.Accept() if err != nil { log.Error("SSH: Accept session channel: %v", err) @@ -119,7 +115,7 @@ func handleSessionChannel(ctx context.Context, conn *gossh.ServerConn, newChan g } defer channel.Close() - session := &sshSession{Channel: channel, conn: conn, ctx: ctx} + session := &sshSession{Channel: channel, conn: conn} for req := range reqs { switch req.Type { case "env": diff --git a/modules/ssh/ssh.go b/modules/ssh/ssh.go index c01a991d63e..e5d0bf06a7a 100644 --- a/modules/ssh/ssh.go +++ b/modules/ssh/ssh.go @@ -64,9 +64,6 @@ func sessionHandler(session *sshSession) int { args := []string{"--config=" + setting.CustomConf, "serv", "key-" + keyID} log.Trace("SSH: Arguments: %v", args) - ctx, cancel := context.WithCancel(session.ctx) - defer cancel() - gitProtocol := "" for _, env := range session.env { if strings.HasPrefix(env, "GIT_PROTOCOL=") { @@ -75,7 +72,7 @@ func sessionHandler(session *sshSession) int { } } - cmd := process.CommandContext(ctx, setting.AppPath, args...) + cmd := process.CommandContext(graceful.GetManager().HammerContext(), setting.AppPath, args...) cmd.Env = append( os.Environ(), "SSH_ORIGINAL_COMMAND="+session.rawCmd,