--- name: ssh-fish-host-remote-exec description: "Runbook for password-auth SSH exec/file-ship to fleet hosts whose login shell is fish (e.g. blankpad), avoiding the fish-parsing and heredoc-swallow traps" --- ## When Running remote commands or shipping files over SSH to a host whose login shell is **fish** (blankpad: user `blank`, reachable only as mDNS FQDN `blankpad.local` / 192.168.0.83 — bare hostname does not resolve from Dankware). ## Procedure 1. **Auth**: `SSHPASS='' sshpass -e ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no user@host '...'` — password via env, never argv (ps-visible). 2. **Remote exec**: `ssh host 'cmd'` pipes the command string to the login shell (fish). Bashisms like `for ... do`, `$?`, heredoc markers fail at *parse* time on fish (`Missing end to balance this for loop`). Always wrap compound commands: `ssh host 'bash -c "for b in a b c; do command -v $b || echo MISSING; done"'` (escape inner `$`). 3. **File shipping**: never combine `cat > /remote/path < /remote/path' < localfile`, then verify byte-truth with md5sum on both ends. 4. **Exit codes**: `$?` in an unquoted remote command is parsed by fish (`$status` there) — wrap in bash or drop the status echo; ssh's own exit code propagates to the caller anyway. ## Why Both traps fired during the 2026-09-09 blankpad dotfiles deploy: first probe attempt died on fish loop parsing; a `cat >` ship silently swallowed the heredoc that was meant for `bash -s`, deploying the wrong file bytes until md5-compared.