a73x

no way to answer an ssh prompt: password, passphrase and unknown-host reach only the tty

open   by a73x

ssh interactive prompts — password auth, a passphrase on an unforwarded
key, and unknown-host confirmation — have exactly one place to go: the
controlling tty. That works for one dial in one of the three places mux
dials from.

**How it stands.** The handoff ssh is spawned with stdin and stdout PIPED
(they are the wire — `client.zig:345` `spawnPipe`) and stderr inherited;
prompts do not read stdin at all, they open `/dev/tty` directly, which is
why `client.zig:487` goes out of its way not to steal cooked lines from
them. Nothing sets `SSH_ASKPASS`, `SSH_ASKPASS_REQUIRE` or `BatchMode`
anywhere in the tree.

- **CLI entry tile: works, deliberately.** `mux HOST` dials on the main
  thread while the tty is still cooked and mux has not taken the screen —
  `wallview.zig:372` and `:1121` both say so in as many words, and `pre` +
  `adopt` exist to carry that link onto the pump thread afterwards.
- **CLI tile grown at runtime, and any reconnect: unclear at best.** A
  chord-grown tile (`Ctrl-\ c`/`n`/`p`) and every redial dial from a pump
  thread, with the terminal in raw mode and the wall painting the screen.
  `/dev/tty` still resolves, so ssh will try; what the user actually sees
  is not something this issue has measured, and it is not the prompt the
  entry path gives them.
- **muxweb: no channel at all.** Every tile dials from its own `pumpTile`
  thread. If the hub was started from a terminal the prompt lands THERE,
  on a terminal nobody is looking at, with N tiles able to prompt onto it
  at once; if the hub was started detached there is no tty and ssh fails
  with no way to say why. The browser — the thing the user is actually
  looking at — has no prompt surface, and `controlMessage`'s vocabulary
  (`webhub.zig:459`) is closed: connecting / up / reconnecting.

**Why it is backlog and not urgent.** The daily path is key auth against
hosts already in `known_hosts`, which prompts for nothing. Shipping
`muxweb -A` (eac95cf4) removes another slice — an agent that answers means
no passphrase prompt for key auth. What survives either way is password
auth, a first connection to an unknown host, and a key whose passphrase
the agent has not got.

**Direction, when it comes up.** `SSH_ASKPASS` plus
`SSH_ASKPASS_REQUIRE=force` (OpenSSH 8.4+, and this box is 10.5) is the
mechanism ssh already offers: a helper mux ships, pointed at a per-dial
channel, so the prompt can be rendered where the user is — a control
message and a page input for muxweb, an overlay for the CLI wall. That
also fixes the interleaving, since each dial names its own channel.
Unknown-host confirmation is the same helper with a different question.
Worth pricing against just documenting "warm the connection once by hand,
then let mux dial it", which is what happens today by accident.

Comments

a73x   2026-08-21 14:03

Related, from the `muxweb -A` review (eac95cf4): a hub that offers a
PROMPT-GATED agent — FIDO touch, or a pinentry that has to ask — has the
same missing surface as an ssh password prompt, and it is worse in one
respect: the sign request just hangs. The `-A` preflight passes regardless,
because listing identities needs no touch, and a sound
unanswered-channel timeout (b316df53) must deliberately NOT kill a
touch-gated signature. So there is nothing to detect it by.

Which means all three of these want the same thing: a way for a tile to
ask the page a question and get an answer back. `controlMessage`'s
vocabulary is closed today (`webhub.zig:459`) — connecting / up /
reconnecting, one direction. Whoever builds the askpass channel should
size it for the other two rather than for ssh alone.