v0.15.0 - Safer SSH Password Automation (2026-07-06)¶
What Changed?¶
This release hardens the pexpect-based SSH password automation in gear.py (tracked as #51): commands are now passed as argv lists instead of a shell-joined string, first-time SSH connections no longer hang or blindly trust an unknown host key, and both the password-prompt and transfer-wait timeouts are configurable and independent of each other.
What's New¶
Main Feature: Hardened SSH Password Automation¶
What it does:
run_rsync()'s password-automation path (gear._run_rsync_with_password) now:
- Spawns
rsyncwith an argv list (pexpect.spawn(cmd[0], args=cmd[1:])) instead of a" ".join(cmd)string, so source/target paths or options containing spaces or shell metacharacters are no longer re-parsed (and potentially broken) by a shell. - Detects the SSH host key confirmation prompt (
Are you sure you want to continue connecting (yes/no)?) that appears on a host's first connection. Previously this wasn't in theexpect()pattern list at all, so fnb would just hang untilTIMEOUT. Now it logs guidance to verify and register the host key manually (ssh-keyscanor a manualsshlogin) and aborts — fnb never auto-confirms an unknown host key. - Reads the password-prompt timeout from a new
FNB_TIMEOUTenvironment variable (env.get_timeout()), instead of a hardcoded 30 seconds. - Uses a separate
transfer_timeout(default: unlimited) for the post-password EOF wait, so a large transfer on a slow link isn't cut off by the same short timeout meant only for detecting the password prompt.
The expect() branches also moved from matching on a positional index (i == 0/1/2) to matching on a name paired with each pattern, so adding or reordering patterns can't silently shift an unrelated branch.
How to use it:
No new flags. Set FNB_TIMEOUT in .env (or the environment) to change how long fnb waits for the SSH password prompt:
If fnb reports a host key verification prompt, connect once manually to accept the key, then retry:
ssh user@example.com # accept the host key interactively
# or
ssh-keyscan -H example.com >> ~/.ssh/known_hosts
fnb fetch logs
Installation¶
Quick Start¶
What's Different from the Last Version?¶
✅ Added¶
env.get_timeout()readsFNB_TIMEOUT(falling back to 30s if unset or invalid)run_rsync()/_run_rsync_with_password()gained atransfer_timeoutparameter, decoupling the transfer-wait timeout from the password-prompt timeoutenv.sampledocuments the newFNB_TIMEOUTvariable
🔧 Changed¶
_run_rsync_with_password()now takes the rsync command as a list (cmd: list[str]) rather than a pre-joined stringexpect()branch matching uses named patterns instead of positional indices
🐛 Fixed¶
pexpect.spawn()no longer breaks on source/target paths or options containing spaces or shell metacharacters- SSH host key confirmation prompts on first-time connections no longer hang until
TIMEOUT— fnb now detects them, logs guidance, and aborts instead of blindly trusting an unverified host - A slow/large transfer is no longer at risk of being cut off by the short password-prompt timeout
Is It Safe to Upgrade?¶
Backward Compatible: Yes.
- Configuration file format (
fnb.toml) and CLI arguments are unchanged FNB_TIMEOUTis optional; if unset, behavior matches the previous hardcoded 30-second default- If you were relying on fnb auto-confirming a host's first SSH connection (it never explicitly did, but would otherwise hang until
TIMEOUT), you'll now see a clear message asking you to verify the host key manually instead of a timeout
Tests Passed¶
- ✅ 132 unit and integration tests passed
- ✅ 89% code coverage
- ✅ All pre-commit hooks pass (mypy, ruff, trailing whitespace, etc.)
Release Details¶
- Date: 2026-07-06
- Version: v0.15.0
- Commits: 4 commits since v0.14.0, all closing out issue #51
370e781: fix(gear): pass rsync command as argv list to pexpect.spawn7e0d4c2: fix(gear): handle SSH host key verification prompt without auto-confirming0f94142: feat(env): make SSH password-prompt timeout configurable via FNB_TIMEOUTd0a6c3b: fix(gear): decouple transfer wait timeout from password-prompt timeout
Next Steps¶
- Continue working through remaining review issues from the 2026-07 codebase review (issue #52 is complete; see the review issue tracker for what's left)