Clean up the agent socket and working files when a signal ends the tool (closes #17)
check / check (push) Successful in 5s

`cli.Main` ran the command tree on a background context, so SIGINT, SIGTERM or SIGHUP killed the process before deferred cleanup ran: `ssh to` left its agent socket and directory behind, and `ssh install` left a copy of the host's `authorized_keys` in its working directory. `Main` now runs the tree on a `signal.NotifyContext` for those signals; the cancelled context ends the child `ssh` or `sftp` and the cleanup runs. `ssh to` stops its child with SIGTERM, not a kill, so `ssh` restores the terminal. Exit status after a signal is 1 unless `ssh` reported its own.

The test re-runs the test binary as the tool, waits for the agent socket, sends each signal and checks the directory is gone.

Disclosure: the repeated `"uptime"` test literal became a `remoteCommand` constant because `goconst` required it.

Model: opus-4-8 (implementation, review); fable-5-1 (merge message)
This commit was merged in pull request #30.
This commit is contained in:
2026-09-21 16:58:24 +02:00
parent 15ebe24f7b
commit 40e9beea8c
4 changed files with 154 additions and 7 deletions
+8
View File
@@ -7,6 +7,7 @@ import (
"os"
"os/exec"
"slices"
"syscall"
"github.com/spf13/cobra"
)
@@ -75,6 +76,13 @@ func connect(ctx context.Context, argv []string) error {
command.Stdout = os.Stdout
command.Stderr = os.Stderr
// A cancelled context means a signal ended the tool. Send ssh a
// SIGTERM rather than the default kill, so it puts the terminal
// back the way it found it before it goes.
command.Cancel = func() error {
return command.Process.Signal(syscall.SIGTERM)
}
err := command.Run()
if err == nil {
return nil