ssh install ends on a signal while sftp's ssh is still connecting (closes #57)
check / check (push) Failing after 1s

A signal during ssh install now sends sftp a SIGTERM instead of killing it, as ssh to already does for ssh, so sftp stops the ssh it started. The sftp command also has a WaitDelay of a quarter second, so a child that still holds sftp's output cannot keep the tool waiting on a host that does not answer: it ends with status 1 and removes its working directory. The test's sftp stand-in now leaves such a child.

Judgement call: exec.ErrWaitDelay counts as success, so a run that used ControlPersist does not report a failure for a key it added.

Model: opus-5-5
Co-authored-by: clawbot <sneak+clawbot@sneak.cloud>
This commit was merged in pull request #58.
This commit is contained in:
2026-10-04 14:25:47 +02:00
committed by clawbot
parent c96b77dd67
commit dad29597bd
2 changed files with 57 additions and 8 deletions
+25
View File
@@ -11,6 +11,8 @@ import (
"path/filepath"
"slices"
"strings"
"syscall"
"time"
"github.com/spf13/cobra"
"sneak.berlin/go/keyfunc/internal/cli/signals"
@@ -34,6 +36,13 @@ const (
localMode = 0o600
)
// waitDelay is the WaitDelay sftp runs with: from a signal, or from sftp
// ending, how long the tool waits for sftp to end and its output to
// close before it kills sftp and stops reading. That is ample for sftp
// to stop the ssh it started, and short enough that a signal still ends
// the tool within a second.
const waitDelay = 250 * time.Millisecond
// ErrCannotEnter is the refusal of a host whose .ssh is there but
// cannot be entered, so that nothing in it can be read or written.
var ErrCannotEnter = errors.New(
@@ -187,8 +196,24 @@ func session(
command.Stdout = &said
command.Stderr = &said
// A cancelled context means a signal arrived. Send sftp a SIGTERM
// rather than the default kill, so it stops the ssh it started
// before it goes. Anything sftp started that still holds its output
// keeps the tool waiting no longer than waitDelay.
command.Cancel = func() error {
return command.Process.Signal(syscall.SIGTERM)
}
command.WaitDelay = waitDelay
err := command.Run()
// sftp ended well and only something it started, such as the
// master ssh leaves running for ControlPersist under -v, still held
// its output: the session worked.
if errors.Is(err, exec.ErrWaitDelay) {
err = nil
}
_, _ = cmd.ErrOrStderr().Write(said.Bytes())
if err != nil {