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.
This commit is contained in:
silverwind authored and GitHub committed 2026-10-31 15:24:13 +00:00
1 parent bd5fbcfb29
commit fc4d490b35
2 files changed
+5 -12

No files matched your search

+4 -8
View File
@@ -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":
+1 -4
View File
@@ -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,