Put the terminal back when a signal ends the mnemonic prompt (closes #91)
check / check (push) Waiting to run

A SIGINT, SIGTERM or SIGHUP at the mnemonic prompt killed the tool
with echo still off. The prompt now catches them with signals.Notify
from before echo goes off, and reads the line in a goroutine. Once the
line is read or a signal arrives, it puts the terminal settings back
and stops catching; if a signal has arrived by then, it sends the tool
the same signal again, so the tool is still ended by it (130 for SIGINT
in a shell). A test sends SIGINT at the prompt on a pseudo-terminal.

The signals package moves from internal/cli to internal/signals, since
the mnemonic prompt now uses it as well.

Unchanged: the Windows prompt, which uses term.ReadPassword.

Model: opus-5-5
This commit is contained in:
2026-10-14 23:05:41 +00:00
parent a08eb28359
commit c3cc26c721
8 changed files with 175 additions and 52 deletions
+10 -7
View File
@@ -65,10 +65,12 @@ calls into `internal/`. The packages there are:
and decrypts with it.
- `internal/childmnemonic` derives a child mnemonic from the main one using
BIP-85's own mnemonic application.
- `internal/signals` catches SIGINT, SIGTERM and SIGHUP for the commands that
clean up before they end, and for the mnemonic prompt, which puts the terminal
back before the signal ends the tool.
- `internal/cli` builds the cobra command tree and runs it. Under it,
`cli/options` holds the flags every command shares, `cli/signals` catches
SIGINT, SIGTERM and SIGHUP for the commands that clean up before they end, and
`cli/ssh`, `cli/age` and `cli/mnemonic` are the command groups.
`cli/options` holds the flags every command shares, and `cli/ssh`, `cli/age`
and `cli/mnemonic` are the command groups.
- `internal/bip39` is a copy of `github.com/tyler-smith/go-bip39` v1.1.0,
trimmed to what keyfunc uses.
@@ -328,10 +330,11 @@ passes through `ssh`'s own exit status.
SIGINT, SIGTERM and SIGHUP end any command at once, at the mnemonic prompt too,
with the status a shell gives a program killed by that signal (130 for SIGINT).
While `age encrypt -o` or `age decrypt -o` is writing a new file or replacing a
regular one, the signal makes it remove the unfinished file, leave a file
already at the named path as it was, and exit with status 1. That holds for a
signal that has reached `keyfunc` when its input ends; a later one leaves the
At the prompt the terminal's settings are put back as they were first, so echo
is on again. While `age encrypt -o` or `age decrypt -o` is writing a new file or
replacing a regular one, the signal makes it remove the unfinished file, leave a
file already at the named path as it was, and exit with status 1. That holds for
a signal that has reached `keyfunc` when its input ends; a later one leaves the
whole file in place. Ctrl-C on a pipeline ends the input at the same moment, and
on Linux `keyfunc` sees the signal first, though no system promises that. A
named pipe or a device at the `-o` path, or a path that is the same file as