Files
Codeman/test
d fei c2492a3523 feat(remote): support password-authenticated SSH hosts, storing the password optionally
The remote path always passed `-o BatchMode=yes`, which disables every
interactive prompt, so password-only hosts could never be used. BatchMode is not
an oversight: Codeman launches ssh non-interactively from a service process with
no terminal and nobody watching, and without it ssh hangs on a password prompt
no one will ever answer — a dead pane, which is worse than an error.

So the password goes through sshpass, handed to ssh in the SSHPASS environment
variable: never in argv (same-host users can read /proc) and never in a temp
file. The variable itself is injected into the pane with socket-scoped
`tmux setenv`, the same rule every other secret here follows.

⚠️ One thing measured, and a naive implementation will hit it: BatchMode=yes and
sshpass are mutually exclusive. The former disables the password prompt, and
answering that prompt is exactly how sshpass works, so using both yields
`Permission denied (publickey,password)` — which reads like a wrong password
rather than wrong arguments. With a password we therefore send BatchMode=no plus
NumberOfPasswordPrompts=1, the latter so a wrong password fails immediately
instead of hanging (also measured).

⚠️ The preflight probe runs in the server process, not in the pane, so
`tmux setenv` does not reach it and that path passes the variable through the
child environment instead. A missing sshpass is reported as a named prerequisite
during the probe as well; otherwise it surfaces as a pane dying with
"sshpass: command not found", which reads like a broken host.

Storage and exposure:
- remote-hosts.json now holds a secret, so it is written 0600, and an existing
  file is explicitly tightened once (writeFile's mode only applies on create)
- the API always redacts, returning only a `passwordSet` boolean
- updates merge the stored password, because a redacted host posted back carries
  no `password` and a straight write would silently erase it; an explicit empty
  string still means "clear"
- the schema deliberately does not apply NO_SHELL_META to `password`: a password
  legitimately contains `$` and backticks, and unlike the path fields it is never
  interpolated into a shell string
2026-09-03 02:01:44 -07:00
..
2026-07-20 17:35:40 +02:00
2026-06-19 17:58:06 -04:00
2026-06-19 17:58:06 -04:00
2026-08-22 14:13:57 +02:00
2026-07-20 02:36:02 +02:00
2026-06-19 13:10:17 -04:00