v0.8.17: per-alias DIRECT (no-multiplex) SSH mode for servers that reject ControlMaster session multiplexing — /ssh-set-direct + per-command sshpass (forced password auth), banner/sudo stderr filter; zero traffic-bypass primitives

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Bryan Johnson 2026-05-28 09:42:37 -07:00
parent 0e6495223a
commit d55e222341
5 changed files with 504 additions and 43 deletions

View File

@ -4,6 +4,91 @@ All notable changes to `cloverleaf-larry` / `larry-anywhere` are recorded here.
Versioning is loose-semver; bumps trigger the in-process self-update on every
running client via `LARRY_BASE_URL` + `MANIFEST`.
## v0.8.17 — 2026-05-28
Per-alias DIRECT (no-multiplex) SSH mode (Clover). The real unblock for
`/sites qa` on Bryan's Legacy→qa box.
**Confirmed root cause (live-verified on the qa box).** The qa server
(`bryjohnx@lhsixfqa` → Cloverleaf host `shdclvf01q`, release cis2025.01)
REJECTS SSH ControlMaster session multiplexing. The master opens and
authenticates fine, but any session multiplexed over it dies with
`read from master failed: Connection reset by peer`, then ssh falls back to a
fresh connection that fails auth. A DIRECT per-command connection WORKS and
returns the 24 site dirs (21 after the helloworld/siteProto/master filter).
**Fix — per-alias DIRECT mode.** A new TSV column 5 (`direct`, on|off) opts an
alias out of the ControlMaster entirely. When on, ALL remote ops for that alias
(`exec`, `discover`, `pull-smat`, `pull`) run a FRESH per-command
`sshpass -f <credfile> ssh -o PreferredAuthentications=password -o
PubkeyAuthentication=no -o StrictHostKeyChecking=accept-new -o ControlMaster=no
-o ControlPath=none -o ConnectTimeout=<n> <user@host> '<remote-cmd>'`. The
remote command is shaped by the SAME `_remote_cmd_for` chokepoint as the master
path, so a pinned HCIROOT (`set-hciroot`) is honoured identically — only the
transport changes. NO traffic bypass: legitimate forced-password auth, no
proxy/tunnel/masking, host-key checking stays on (accept-new).
1. `lib/ssh-helper.sh` — TSV column 5 (`direct`); `read_host_direct` /
`_alias_is_direct` readers; `cmd_set_direct` (`set-direct <alias> on|off`,
whitespace-trimmed, legacy <5-column files backfilled, pinned HCIROOT in
col 4 never clobbered); `_run_direct` (per-command sshpass dispatch +
stderr filtering); `_direct_scp` (fresh-sshpass scp for pull); centralised
`_dispatch_remote` (direct vs master, identical command shaping); `cmd_exec`
/ `cmd_discover` / `cmd_pull_smat` / `cmd_pull` route through it and SKIP the
open-master requirement in direct mode; `cmd_setup` in direct mode VALIDATES
the stored password with one trivial direct command instead of opening a
(pointless) master; `cmd_hosts` shows the `direct` column (`master=n/a` for
direct aliases). New `set-direct|direct` subcommand + help.
2. `larry.sh``/ssh-set-direct <alias> on|off` slash command (set-u-safe
split, the v0.8.16 idiom); added to the completion array + descriptions +
`print_help`; `tool_list_sites` reports the transport (`direct sshpass` vs
`ControlMaster`) and gives a transport-correct recovery hint on discover
failure (stale password in direct mode, not "closed master"); `list_sites`
tool description + the system-prompt remote-alias guidance updated for the
multiplex-rejection symptom and the `/ssh-set-direct` recovery.
**Clean output (UX).** The qa login profile emits a pre-auth banner
("Unauthorized access…/monitored") AND `sudo: a terminal is required` /
`sudo: a password is required` on STDERR for non-interactive sessions. The
parsed site list is on STDOUT (already clean). `_filter_direct_stderr` strips
exactly those known-benign lines; remaining stderr is surfaced ONLY on an
actual non-zero command failure. So `/sites qa` shows just the 21 sites + the
`(excluded: …)` note — no banner/sudo noise.
**No regression.** Aliases WITHOUT the direct flag keep the existing
ControlMaster-multiplex path unchanged (and still die "no open master" when
none is open).
**New flow for qa.** `/ssh-pass qa` → `/ssh-set-hciroot qa
/hci/cis2025.01/integrator` → `/ssh-set-direct qa on``/sites qa`. No master
step in direct mode.
**Self-verify (this gate, pre-Vera).** Driven non-interactively on this Mac:
flag round-trip (add → set-direct on/off → hosts → raw TSV; col 4 HCIROOT
preserved across col 5 writes); legacy 3-column file backfilled to 5 columns;
command-shaping (`_remote_cmd_for`) identical pinned-export for direct and
master, login-shell for unpinned; `_alias_is_direct` 0/1; stderr filter against
a sample banner+sudo+real-error (only the genuine `find: … Permission denied`
survives; pure banner+sudo → empty); `_run_direct` end-to-end via a stubbed
`sshpass` — STDOUT clean + STDERR empty on success, real error surfaced + banner
stripped + rc propagated on failure; `tool_list_sites qa` over a stubbed direct
discover → `sites: 21 (excluded: helloworld, siteProto, master)`, clean,
correct mode line; direct-mode `setup`/`discover` skip the open-master die;
non-direct `exec`/`discover` still die "no open master" (no regression); and the
`/ssh-set-direct` REPL slash handler (+ neighbours `/ssh-set-hciroot`,
`/ssh-setup`, `/ssh`) drive through a `case` dispatcher under `set -u` +
`compat32` with no unbound-variable abort and correct routing. (Live connect to
the qa box not run here — `sshpass` is the production host's tool, absent on the
Mac; the path up to the sshpass invocation is fully exercised via the stub.)
**Vera v0.8.16 caveat closed (evidence attached).** Repo-wide self-ref-class
grep `grep -rnE '^[[:space:]]*(local|declare|typeset|readonly|export)[[:space:]]+[A-Za-z_].*=.*$' larry.sh lib/`
(712 superficial matches) + a targeted same-statement self-reference detector:
**ZERO** same-statement self-references — every match is the safe sequential
`;`-separated idiom. `bash -n larry.sh lib/*.sh` → clean (36/36 files OK).
---
## v0.8.16 — 2026-05-28
Hotfix (Clover): `set -u` unbound-variable abort in the v0.8.15

View File

@ -23,16 +23,16 @@
# scripts/make-manifest.sh and bump VERSION.
# Top-level scripts
larry.sh 7bbd920f7a29379aadad3e59a298ff416333e9299241db7c7bb8c42cc7750f9d
larry.sh 7bdbe0743d7aec58ccedadfebd766e8bbfd828d47e33e51b2bac75a4d0706f5b
larry-tunnel.sh 6b050e4eeab15669f4858eaf3b807f168f211ced07815db9521bc40a093f6aaa
larry-auth.sh a220cdf7878569dc3028951ee57fc8d5e706a8ca5c6aa45347b58facb386f831
larry-rollback.sh 91b5e9aa6c79266bf306dcfba4ca791c07971bd6924d67a779037531648aa6d0
install-larry.sh e97da4e12a0d8863ca18d79b12f6c4294c72fa6d4b11dffeab66504236bb4eb1
# Metadata
VERSION 088faf7f331988e309c37e27272af81cd41fdcf4466022059ffdd3184e3c7d34
VERSION a8c64c5df539331e33b8b4b5c1534d12f6238dbbbd313e7cebbf1cff1df0fe87
MANUAL.md 666128a086b59ff3c31a574aec0c5dd681666d66319da9f078451bf9013ca5e1
CHANGELOG.md 3db03a7913b3a66310f9cb282eaa6c3554d5ed59ef92eca78ef02257dc97277f
CHANGELOG.md a329fda8be2e5caa33f1dfec7a5c68adc7d7d19b8449032cbfc9542a766292b6
# Agent personas (system-prompt overlays)
agents/larry.md 11ea905fa7cac6fa7baeb11b2d62af07b15a666ce90cfe36491bcbc555244397
@ -52,7 +52,7 @@ lib/fetch-safe.sh abecf0045b9856f63ffa346119443c11de56547344be32bddaed9fbae6b021
lib/oauth.sh 04a93376f88fe53cc1c86a5dbe577735c60375dadd4f2fda55b921ef3cddf22b
# Secure SSH with ControlMaster (password hidden from Larry-the-LLM)
lib/ssh-helper.sh 3397945df8184d0bc89853608c097af11b97b37695c5598c979347b6b912e0eb
lib/ssh-helper.sh e9e2f33bb893d951e668d81dfe88057d235013b60cdba0e3441d1400d877a6d4
# v0.8.6: work-box → Mac headers.log sync (tsk-2026-05-27-023). Incremental,
# offset-tracked push of $LARRY_HOME/log/headers.log to a daemon-watched path

View File

@ -1 +1 @@
0.8.16
0.8.17

View File

@ -78,7 +78,7 @@ set -o pipefail
# ─────────────────────────────────────────────────────────────────────────────
# Config
# ─────────────────────────────────────────────────────────────────────────────
LARRY_VERSION="0.8.16"
LARRY_VERSION="0.8.17"
LARRY_HOME="${LARRY_HOME:-$HOME/.larry}"
# ─────────────────────────────────────────────────────────────────────────────
@ -1247,7 +1247,7 @@ detect_cloverleaf_env() {
esac
if [ -n "$aliases" ]; then
lines+=("Configured SSH aliases: $(printf '%s' "$aliases" | tr '\n' ' ')")
lines+=("For a remote alias: discover its env with the list_sites tool (alias=<name>) — it resolves the remote \$HCIROOT (login shell, or an explicit pin if set) and walks NetConfigs. NEVER ask Bryan to export \$HCIROOT for a remote host. If list_sites reports HCIROOT empty with a sudo-gated-profile NOTE, have Bryan pin it once: /ssh-set-hciroot <alias> <path> (e.g. qa → /hci/cis2025.01/integrator).")
lines+=("For a remote alias: discover its env with the list_sites tool (alias=<name>) — it resolves the remote \$HCIROOT (login shell, or an explicit pin if set) and walks NetConfigs. NEVER ask Bryan to export \$HCIROOT for a remote host. If list_sites reports HCIROOT empty with a sudo-gated-profile NOTE, have Bryan pin it once: /ssh-set-hciroot <alias> <path> (e.g. qa → /hci/cis2025.01/integrator). If a remote op fails with 'read from master failed: Connection reset by peer' (the host rejects SSH session multiplexing), have Bryan switch that alias to DIRECT mode: /ssh-set-direct <alias> on — then ALL remote ops use a fresh per-command sshpass connection (no ControlMaster). In DIRECT mode the recovery for a discover failure is a stale password (/ssh-pass then /ssh-setup to re-validate), NOT a closed master.")
fi
if [ -n "${HCIROOT:-}" ]; then
@ -3833,8 +3833,20 @@ tool_list_sites() {
local out rc
out=$("$helper" discover "$alias" 2>&1); rc=$?
if [ "$rc" -ne 0 ]; then
# v0.8.17: the recovery hint depends on the alias's transport mode. In
# DIRECT mode there is no master — a failure is most likely a stale/rotated
# password (re-run /ssh-pass then /ssh-setup to re-validate). In master mode
# the usual cause is a closed master (re-run /ssh-setup).
local _ls_direct=""
local _ls_tsv="${LARRY_HOME:-$HOME/.larry}/.ssh-hosts.tsv"
[ -f "$_ls_tsv" ] && _ls_direct=$(awk -F'\t' -v a="$alias" 'NR>1 && $1==a && $5=="on"{print "on"; exit}' "$_ls_tsv" 2>/dev/null)
if [ "$_ls_direct" = "on" ]; then
printf '%s\n[list_sites: discover failed for alias=%s rc=%d (DIRECT mode). Likely a stale/rotated password — tell Bryan to re-run /ssh-pass %s then /ssh-setup %s to re-validate.]\n' \
"$out" "$alias" "$rc" "$alias" "$alias"
else
printf '%s\n[list_sites: discover failed for alias=%s rc=%d. If the master is closed, tell Bryan to run /ssh-setup %s]\n' \
"$out" "$alias" "$rc" "$alias"
fi
return 0
fi
local rroot; rroot=$(printf '%s\n' "$out" | awk -F'\t' '$1=="HCIROOT"{print $2; exit}')
@ -3849,11 +3861,14 @@ tool_list_sites() {
# v0.8.15: report the actual resolution mode. If the alias has a pinned
# HCIROOT (4th column of the hosts TSV) the discover ran with HCIROOT
# exported explicitly and NO login profile; otherwise it used a login shell.
local _hosts_tsv="${LARRY_HOME:-$HOME/.larry}/.ssh-hosts.tsv" _pin="" _mode="login shell"
local _hosts_tsv="${LARRY_HOME:-$HOME/.larry}/.ssh-hosts.tsv" _pin="" _direct="" _mode="login shell"
if [ -f "$_hosts_tsv" ]; then
_pin=$(awk -F'\t' -v a="$alias" 'NR>1 && $1==a { print $4; exit }' "$_hosts_tsv" 2>/dev/null)
_direct=$(awk -F'\t' -v a="$alias" 'NR>1 && $1==a && $5=="on" { print "on"; exit }' "$_hosts_tsv" 2>/dev/null)
fi
[ -n "$_pin" ] && _mode="pinned HCIROOT, no login profile"
# v0.8.17: note the transport too — direct (per-command sshpass) vs master.
if [ "$_direct" = "on" ]; then _mode="$_mode; direct sshpass"; else _mode="$_mode; ControlMaster"; fi
printf 'Cloverleaf env on alias "%s" (REMOTE, %s):\n' "$alias" "$_mode"
printf ' HCIROOT = %s\n' "${rroot:-<unresolved>}"
[ -n "$note" ] && printf ' NOTE: %s\n' "$note"
@ -4140,7 +4155,7 @@ TOOLS_JSON=$(cat <<'TOOLS_END'
{"name":"ssh_exec","description":"Run a shell command on a remote test/dev host via an authenticated SSH ControlMaster session. Bryan must have already configured the alias (via /ssh-add) and opened the master (via /ssh-setup). The password is stored locally and you CANNOT see it — do not ask Bryan for it; if the master is closed, tell him to run the /ssh-setup ALIAS slash command. Use ssh_status first to confirm which aliases are open. Output capped at max_lines (default 500). Tool result includes the remote exit code as a [ssh_exec: exit rc=N] footer.","input_schema":{"type":"object","properties":{"alias":{"type":"string","description":"Host alias Bryan configured. Run ssh_status to see the list."},"command":{"type":"string","description":"Shell command to execute on the remote. Quote as needed; will be passed through ssh as a single string."},"max_lines":{"type":"integer","description":"Cap output lines (default 500). Increase for known-large output, but prefer targeted commands."}},"required":["alias","command"]}},
{"name":"ssh_status","description":"List the SSH hosts Bryan has configured and which ones have an open ControlMaster session. Call this BEFORE ssh_exec to confirm an alias exists and the master is open. Each line shows: alias, user@host, port, cred (present/absent), master (open or dash). If the master is not open for an alias you need, ask Bryan to run the /ssh-setup ALIAS slash command. Do NOT attempt to authenticate yourself — you have no access to the password.","input_schema":{"type":"object","properties":{},"required":[]}},
{"name":"list_sites","description":"List and COUNT the Cloverleaf sites in the environment. This is your proactive answer to 'how many sites are on <X>' / 'what sites exist' — NEVER ask Bryan to export or hand you $HCIROOT first; this tool resolves it for you. Works in BOTH deployment modes. REMOTE mode: pass alias=<name> (a configured SSH alias, e.g. qa); the tool resolves the remote $HCIROOT and enumerates sites via a NetConfig walk (the version-agnostic ground truth; Cloverleaf's hcisitelist is used only if present AND the walk found nothing). If the alias has a PINNED HCIROOT (set via /ssh-set-hciroot), the walk runs with HCIROOT exported explicitly and SKIPS the login profile — this is required on hosts whose login profile is sudo-gated/non-interactive (a plain login shell there returns an EMPTY $HCIROOT). Otherwise it opens a LOGIN shell so the operator profile populates $HCIROOT. The ControlMaster must be open — if it is not, the result tells you to have Bryan run /ssh-setup <alias>. If the result shows HCIROOT empty with a NOTE about a sudo-gated profile, tell Bryan to pin it: /ssh-set-hciroot <alias> <path>. LOCAL mode: omit alias; the tool enumerates sites under the locally-detected $HCIROOT (or the hciroot override). Returns the resolved HCIROOT, a site count, and the site names.","input_schema":{"type":"object","properties":{"alias":{"type":"string","description":"REMOTE mode: an SSH alias from ssh_status (e.g. 'qa'). Omit for LOCAL mode (sites on this box)."},"hciroot":{"type":"string","description":"LOCAL mode only: override the detected $HCIROOT."}},"required":[]}},
{"name":"list_sites","description":"List and COUNT the Cloverleaf sites in the environment. This is your proactive answer to 'how many sites are on <X>' / 'what sites exist' — NEVER ask Bryan to export or hand you $HCIROOT first; this tool resolves it for you. Works in BOTH deployment modes. REMOTE mode: pass alias=<name> (a configured SSH alias, e.g. qa); the tool resolves the remote $HCIROOT and enumerates sites via a NetConfig walk (the version-agnostic ground truth; Cloverleaf's hcisitelist is used only if present AND the walk found nothing). If the alias has a PINNED HCIROOT (set via /ssh-set-hciroot), the walk runs with HCIROOT exported explicitly and SKIPS the login profile — this is required on hosts whose login profile is sudo-gated/non-interactive (a plain login shell there returns an EMPTY $HCIROOT). Otherwise it opens a LOGIN shell so the operator profile populates $HCIROOT. TRANSPORT: if the alias is in DIRECT mode (set via /ssh-set-direct <alias> on — for hosts that reject SSH session multiplexing) the walk runs over a fresh per-command sshpass connection and NO ControlMaster is needed; otherwise the ControlMaster must be open and if it is not, the result tells you to have Bryan run /ssh-setup <alias>. If the result shows HCIROOT empty with a NOTE about a sudo-gated profile, tell Bryan to pin it: /ssh-set-hciroot <alias> <path>. LOCAL mode: omit alias; the tool enumerates sites under the locally-detected $HCIROOT (or the hciroot override). Returns the resolved HCIROOT, a site count, and the site names.","input_schema":{"type":"object","properties":{"alias":{"type":"string","description":"REMOTE mode: an SSH alias from ssh_status (e.g. 'qa'). Omit for LOCAL mode (sites on this box)."},"hciroot":{"type":"string","description":"LOCAL mode only: override the detected $HCIROOT."}},"required":[]}},
{"name":"hl7_diff","description":"HL7-aware diff between two message files (or multi-message dumps). Compares segment-by-segment, field-by-field, with component and subcomponent precision. Ignores configured fields (default MSH.7 timestamp) so timestamp-only diffs do not show up as noise. Use for regression testing between environments (e.g. test vs prod route-test outputs).","input_schema":{"type":"object","properties":{"left":{"type":"string","description":"Path to left HL7 file."},"right":{"type":"string","description":"Path to right HL7 file."},"ignore":{"type":"string","description":"Comma-separated list of fields to ignore (e.g. MSH.7,MSH.10,EVN.6). Default MSH.7."},"include":{"type":"string","description":"If set, ONLY these fields are compared (overrides ignore for that set)."},"format":{"type":"string","enum":["text","tsv","count"],"description":"text=human-readable diff, tsv=machine-parseable, count=just the difference count."}},"required":["left","right"]}},
@ -5452,7 +5467,14 @@ Slash commands:
/ssh-set-hciroot <alias> <path> pin HCIROOT for an alias (sudo-gated/non-interactive
hosts that don't export it in a non-login shell;
empty path clears the pin)
/ssh-set-direct <alias> on|off DIRECT (no-multiplex) mode: ALL remote ops for the
alias run a FRESH per-command sshpass connection,
bypassing the ControlMaster — for hosts that reject
SSH session multiplexing ("read from master failed:
Connection reset by peer"). off (or empty) reverts.
/ssh-setup <alias> open a long-lived ControlMaster connection
(DIRECT mode: skips the master, just validates the
stored password with one direct command)
/ssh-close <alias> close the ControlMaster
/ssh-status [alias] show open masters + cred presence
/ssh <alias> <command> run command on the remote (you-driven, ad-hoc)
@ -5706,6 +5728,7 @@ _LARRY_SLASH_CMDS=(
/ssh-remove
/ssh-pass
/ssh-set-hciroot
/ssh-set-direct
/ssh-setup
/ssh-close
/ssh-status
@ -5764,7 +5787,8 @@ _LARRY_SLASH_CMDS_DESC=(
[/ssh-remove]="<alias> remove a host"
[/ssh-pass]="<alias> set/update password (hidden input)"
[/ssh-set-hciroot]="<alias> <path> pin HCIROOT for an alias (sudo-gated hosts; empty path clears)"
[/ssh-setup]="<alias> open a long-lived ControlMaster"
[/ssh-set-direct]="<alias> on|off toggle DIRECT no-multiplex SSH (hosts that reject ControlMaster)"
[/ssh-setup]="<alias> open a long-lived ControlMaster (DIRECT mode: validates password, no master)"
[/ssh-close]="<alias> close the ControlMaster"
[/ssh-status]="show open ControlMaster sessions + cred presence"
[/redetect]="re-scan for HCIROOT/HCISITE/tools"
@ -6913,6 +6937,27 @@ main_loop() {
# _sh_path may legitimately be empty (clear the pin).
_run_ssh_helper set-hciroot "$_sh_alias" "$_sh_path"
continue ;;
/ssh-set-direct*) # v0.8.17: toggle DIRECT (no-multiplex) mode for an alias.
# When on, ALL remote ops bypass the ControlMaster and run a
# fresh per-command sshpass connection (for hosts that reject
# SSH session multiplexing, e.g. qa → shdclvf01q).
local rest; rest=$(_slash_args "/ssh-set-direct" "$input")
if [ -z "$rest" ]; then
err "usage: /ssh-set-direct <alias> on|off"; continue
fi
# set-u-safe split (same idiom as /ssh-set-hciroot): declare
# first, assign the alias, THEN reference it. A single-line
# `local a=… b="…$a…"` aborts under set -u (bash 3.2/Cygwin AND
# modern bash) — the v0.8.16 bug class.
local _sd_alias _sd_mode
_sd_alias="${rest%% *}"
_sd_mode="${rest#"$_sd_alias"}"; _sd_mode="${_sd_mode# }"
if [ -z "$_sd_alias" ]; then
err "usage: /ssh-set-direct <alias> on|off"; continue
fi
# _sd_mode empty → treated as "off" (clear) by the helper.
_run_ssh_helper set-direct "$_sd_alias" "$_sd_mode"
continue ;;
/ssh-setup*) local rest; rest=$(_slash_args "/ssh-setup" "$input")
if [ -z "$rest" ]; then err "usage: /ssh-setup <alias>"; continue; fi
_run_ssh_helper setup "$rest"

View File

@ -27,7 +27,25 @@
# hosts whose login profile is sudo-gated or
# otherwise non-interactive (v0.8.15).
# Pass an empty path to clear the pin.
# setup <alias> open ControlMaster (uses stored password ONCE)
# set-direct <alias> on|off toggle (persist) DIRECT mode for an alias
# (v0.8.17). When ON, ALL remote ops for the
# alias BYPASS the ControlMaster and run a
# FRESH per-command sshpass connection with
# forced password auth. For hosts that reject
# SSH session multiplexing ("read from master
# failed: Connection reset by peer") — the
# master opens but multiplexed sessions die.
# The pinned HCIROOT (set-hciroot) is still
# honoured: the remote command is shaped by
# the same _remote_cmd_for path, just sent
# over the direct connection. NO traffic
# bypass — plain forced-password ssh, no
# proxy/tunnel/masking, host-key checked
# (accept-new). Persisted as TSV column 5.
# setup <alias> open ControlMaster (uses stored password ONCE).
# In DIRECT mode, skips the (pointless) master
# and instead VALIDATES the password with one
# trivial direct command, then reports ready.
# close <alias> close ControlMaster
# status [alias] show open masters / cred presence
# exec <alias> <command...> run command via master (returns output)
@ -77,7 +95,9 @@ ensure_layout() {
umask 077
# v0.8.15: 4th column = pinned HCIROOT (optional). Older 3-column files stay
# valid — readers treat a missing $4 as "no pin".
printf 'alias\taddr\tport\thciroot\n' > "$SSH_HOSTS_FILE"
# v0.8.17: 5th column = direct flag (on|off, optional). Older 3-/4-column
# files stay valid — readers treat a missing/empty $5 as "off" (master mode).
printf 'alias\taddr\tport\thciroot\tdirect\n' > "$SSH_HOSTS_FILE"
chmod 600 "$SSH_HOSTS_FILE"
fi
}
@ -98,13 +118,28 @@ read_host_hciroot() {
awk -F'\t' -v a="$alias" 'NR>1 && $1==a { print $4; exit }' < "$SSH_HOSTS_FILE"
}
# read_host_direct ALIAS → echoes "on" if DIRECT mode is set (column 5 == on),
# else empty. v0.8.17: when on, ALL remote ops for the alias bypass the
# ControlMaster and run a fresh per-command sshpass connection (for hosts that
# reject session multiplexing). Missing/empty/anything-but-"on" → master mode.
read_host_direct() {
local alias="$1"
[ -f "$SSH_HOSTS_FILE" ] || { printf ''; return 0; }
awk -F'\t' -v a="$alias" 'NR>1 && $1==a && $5=="on" { print "on"; exit }' < "$SSH_HOSTS_FILE"
}
# _alias_is_direct ALIAS → returns 0 (true) if the alias is in DIRECT mode.
_alias_is_direct() {
[ "$(read_host_direct "$1")" = "on" ]
}
require_sshpass() {
command -v sshpass >/dev/null 2>&1 \
|| die "sshpass not on PATH — install it (apt install sshpass / brew install sshpass) and retry"
}
cmd_help() {
sed -n '4,47p' "$0"
sed -n '4,65p' "$0"
}
cmd_hosts() {
@ -115,17 +150,26 @@ cmd_hosts() {
echo "no hosts configured. Add with: ssh-helper.sh add <alias> <user@host[:port]>"
return 0
fi
printf 'alias user@host port cred master hciroot-pin\n'
printf '%s\n' '───── ───────── ──── ──── ────── ───────────'
awk -F'\t' 'NR>1' "$SSH_HOSTS_FILE" | while IFS=$'\t' read -r alias addr port hciroot; do
printf 'alias user@host port cred master direct hciroot-pin\n'
printf '%s\n' '───── ───────── ──── ──── ────── ────── ───────────'
awk -F'\t' 'NR>1' "$SSH_HOSTS_FILE" | while IFS=$'\t' read -r alias addr port hciroot direct; do
local cred_state=""
[ -f "$SSH_CREDS_DIR/$alias" ] && cred_state="✓"
# v0.8.17: in DIRECT mode the master column reads "n/a" — there is no master
# to probe (and probing it would be a meaningless socket check). The direct
# column shows on/.
local direct_state=""
[ "$direct" = "on" ] && direct_state="on"
local master_state=""
if [ "$direct" = "on" ]; then
master_state="n/a"
else
local sock="$SSH_SOCKETS_DIR/$alias.sock"
if [ -S "$sock" ] && ssh -S "$sock" -O check -p "$port" "$addr" 2>/dev/null; then
master_state="open"
fi
printf '%-20s%-52s%-6s%-6s%-8s%s\n' "$alias" "$addr" "${port:-22}" "$cred_state" "$master_state" "${hciroot:-}"
fi
printf '%-20s%-52s%-6s%-6s%-8s%-8s%s\n' "$alias" "$addr" "${port:-22}" "$cred_state" "$master_state" "$direct_state" "${hciroot:-}"
done
}
@ -149,7 +193,8 @@ cmd_add() {
fi
umask 077
# v0.8.15: write an empty 4th (hciroot) field so the row layout is uniform.
printf '%s\t%s\t%s\t%s\n' "$alias" "$addr" "$port" "" >> "$SSH_HOSTS_FILE"
# v0.8.17: write an empty 5th (direct) field too — uniform 5-column rows.
printf '%s\t%s\t%s\t%s\t%s\n' "$alias" "$addr" "$port" "" "" >> "$SSH_HOSTS_FILE"
chmod 600 "$SSH_HOSTS_FILE"
ok "added $alias$addr (port $port). Next: ssh-helper.sh pass $alias"
}
@ -167,10 +212,12 @@ cmd_set_hciroot() {
local addr_port; addr_port=$(read_host_addr "$alias")
[ -n "$addr_port" ] || die "no such alias: $alias (run 'add' first)"
# Rewrite the row in place, setting/replacing column 4. awk handles rows that
# still have only 3 columns (legacy) by assigning $4 directly.
# still have only 3 columns (legacy) by assigning $4 directly. v0.8.17: also
# backfill the column-5 (direct) header so the layout stays uniform; existing
# column-5 values on data rows are preserved untouched (we only touch $4).
local tmp; tmp=$(mktemp)
awk -F'\t' -v OFS='\t' -v a="$alias" -v r="$newroot" '
NR==1 { if (NF < 4) { $4="hciroot" } print; next }
NR==1 { if (NF < 4) { $4="hciroot" } if (NF < 5) { $5="direct" } print; next }
$1==a { $4=r; print; next }
{ print }
' "$SSH_HOSTS_FILE" > "$tmp" && mv "$tmp" "$SSH_HOSTS_FILE"
@ -183,6 +230,51 @@ cmd_set_hciroot() {
fi
}
# cmd_set_direct ALIAS on|off — toggle (or clear) DIRECT mode for an alias.
# Persisted as column 5 of the hosts TSV. v0.8.17.
#
# When ON, cmd_exec/cmd_discover/cmd_pull_smat run remote commands over a FRESH
# per-command sshpass connection (forced password auth) instead of multiplexing
# through a ControlMaster socket — the fix for hosts (e.g. qa → shdclvf01q) where
# the master opens & authenticates fine but any multiplexed session dies with
# "read from master failed: Connection reset by peer". The pinned HCIROOT (set
# via set-hciroot) is still honoured — the remote command is shaped by the same
# _remote_cmd_for path; only the dispatch (direct vs master socket) changes.
cmd_set_direct() {
local alias="${1:-}" mode="${2:-}"
[ -n "$alias" ] || die "usage: set-direct <alias> on|off"
# Trim surrounding whitespace so a trailing-space arg from the slash path
# (e.g. `/ssh-set-direct qa on `) still normalizes cleanly to on|off.
mode="${mode#"${mode%%[![:space:]]*}"}" # leading
mode="${mode%"${mode##*[![:space:]]}"}" # trailing
case "$mode" in
on|ON|On) mode="on" ;;
off|OFF|Off|'') mode="" ;; # empty/off → clear the flag (master mode)
*) die "usage: set-direct <alias> on|off (got: $mode)" ;;
esac
ensure_layout
local addr_port; addr_port=$(read_host_addr "$alias")
[ -n "$addr_port" ] || die "no such alias: $alias (run 'add' first)"
# Rewrite the row in place, setting/replacing column 5. awk backfills the
# column-4 (hciroot) and column-5 (direct) headers for legacy <5-column files,
# and pads a matching data row to 5 columns before assigning $5 so we never
# clobber a pinned HCIROOT in column 4.
local tmp; tmp=$(mktemp)
awk -F'\t' -v OFS='\t' -v a="$alias" -v m="$mode" '
NR==1 { if (NF < 4) { $4="hciroot" } if (NF < 5) { $5="direct" } print; next }
$1==a { if (NF < 4) { $4="" } $5=m; print; next }
{ print }
' "$SSH_HOSTS_FILE" > "$tmp" && mv "$tmp" "$SSH_HOSTS_FILE"
chmod 600 "$SSH_HOSTS_FILE"
if [ "$mode" = "on" ]; then
ok "DIRECT mode ON for $alias"
ok " (all remote ops bypass the ControlMaster — fresh per-command sshpass, forced password auth)"
ok " next: ssh-helper.sh setup $alias (validates the password; no master opened in direct mode)"
else
ok "DIRECT mode OFF for $alias (reverting to ControlMaster multiplexing)"
fi
}
cmd_remove() {
local alias="${1:-}"
[ -n "$alias" ] || die "usage: remove <alias>"
@ -225,6 +317,48 @@ cmd_setup() {
addr=$(printf '%s' "$addr_port" | cut -f1)
port=$(printf '%s' "$addr_port" | cut -f2)
ensure_layout
# v0.8.17: DIRECT mode — opening a ControlMaster is pointless (the box rejects
# multiplexing). Instead, VALIDATE that the stored password authenticates by
# running one trivial direct command, then report ready. No master socket is
# created. This makes Bryan's flow:
# /ssh-pass <a> → /ssh-set-hciroot <a> <path> → /ssh-set-direct <a> on → /sites <a>
if _alias_is_direct "$alias"; then
local credfile="$SSH_CREDS_DIR/$alias"
[ -f "$credfile" ] || die "no password set for $alias — run 'pass $alias' first"
require_sshpass
ok "DIRECT mode for $alias ($addr:$port) — validating the stored password (no master in direct mode)..."
local errfile; errfile=$(mktemp 2>/dev/null || echo "/tmp/larry-ssh-direct-setup.err.$$")
# A trivial, side-effect-free probe. Forced password auth, host-key checked,
# no master. STDERR (banner/sudo) is captured for failure diagnosis only.
sshpass -f "$credfile" ssh \
-o "PreferredAuthentications=password" \
-o "PubkeyAuthentication=no" \
-o "NumberOfPasswordPrompts=1" \
-o "StrictHostKeyChecking=accept-new" \
-o "ControlMaster=no" \
-o "ControlPath=none" \
-o "ConnectTimeout=$_DIRECT_CONNECT_TIMEOUT" \
-p "$port" \
"$addr" 'true' 2>"$errfile"
local vrc=$?
if [ "$vrc" -eq 0 ]; then
rm -f "$errfile"
ok "✓ direct auth OK: $alias$addr:$port (no master; ready for /sites $alias)"
return 0
fi
printf 'ssh-helper: direct validation FAILED for %s (rc=%d).\n' "$alias" "$vrc" >&2
local filtered; filtered=$(_filter_direct_stderr < "$errfile")
if [ -n "$filtered" ]; then
printf 'ssh-helper: remote stderr (benign banner/sudo lines stripped):\n' >&2
printf '%s\n' "$filtered" >&2
else
printf 'ssh-helper: no non-benign stderr — almost certainly the stored password is stale/rotated. Re-run: ssh-helper.sh pass %s\n' "$alias" >&2
fi
rm -f "$errfile"
return 1
fi
local sock="$SSH_SOCKETS_DIR/$alias.sock"
if [ -S "$sock" ] && ssh -S "$sock" -O check -p "$port" "$addr" 2>/dev/null; then
ok "master already open for $alias ($addr:$port)"
@ -432,12 +566,146 @@ _remote_cmd_for() {
fi
}
cmd_exec() {
local alias="${1:-}"
[ -n "$alias" ] || die "usage: exec <alias> <command...>"
shift
local cmd="$*"
[ -n "$cmd" ] || die "no command given"
# ── v0.8.17: DIRECT (no-multiplex) dispatch ──────────────────────────────────
#
# Some Cloverleaf hosts reject SSH ControlMaster session multiplexing: the master
# opens and authenticates, but every session multiplexed over it dies with
# "read from master failed: Connection reset by peer", then ssh falls back to a
# fresh connection that fails auth. Confirmed live on qa (bryjohnx@lhsixfqa →
# shdclvf01q, cis2025.01). The fix is to run each remote command as its OWN
# fresh ssh connection with forced password auth (sshpass -f <credfile>) — NO
# master socket. This is legitimate password auth, NOT a traffic bypass: no
# proxy, no tunnel, no masking, and host-key checking stays on (accept-new).
#
# _DIRECT_CONNECT_TIMEOUT — seconds for ssh ConnectTimeout (env-overridable).
_DIRECT_CONNECT_TIMEOUT="${LARRY_SSH_DIRECT_TIMEOUT:-10}"
# _direct_creds ALIAS → echoes the credfile path (the file /ssh-pass writes),
# or empty (and warns) if absent. Same file the ControlMaster path uses.
_direct_creds() {
local alias="$1"
local credfile="$SSH_CREDS_DIR/$alias"
[ -f "$credfile" ] && { printf '%s' "$credfile"; return 0; }
printf ''
return 1
}
# _filter_direct_stderr — strip known-benign noise from a direct session's
# STDERR so the parsed STDOUT result is presented clean. The qa login profile
# emits a pre-auth banner ("Unauthorized access…/monitored", "WARNING", etc.)
# AND `sudo: a terminal is required` / `sudo: a password is required` /
# `sudo: no tty present` on STDERR for non-interactive sessions. Those are
# expected and harmless for our read-only enumeration — drop them. ANYTHING
# ELSE that remains is a real signal and is surfaced by the caller, but ONLY on
# an actual non-zero command failure (see _run_direct). Reads stderr on stdin;
# echoes the filtered remainder. The patterns are intentionally narrow so we
# never swallow a genuine error message.
_filter_direct_stderr() {
grep -ivE \
'unauthorized (access|use)|access is monitored|monitored and recorded|this (system|computer|is a) .*(private|restricted|government|corporate)|by (logging in|accessing|using) .*(you )?(consent|agree)|all activ(ity|ities) .*(may be|are) (monitored|logged|recorded)|disconnect immediately|^[[:space:]]*\*+[[:space:]]*$|^[[:space:]]*WARNING[[:space:]]*[:!]?|sudo: a terminal is required|sudo: a password is required|sudo: no tty present|sudo: sorry, you must have a tty' \
2>/dev/null || true
}
# _run_direct ALIAS REMOTE_CMD → run REMOTE_CMD on ALIAS over a FRESH per-command
# sshpass connection (no ControlMaster). REMOTE_CMD must already be shaped by
# _remote_cmd_for (so the HCIROOT pin / login-shell wrapper is honoured). STDOUT
# is passed through verbatim (the parsed-clean result). STDERR is captured,
# filtered for the known-benign banner+sudo lines, and surfaced ONLY when the
# remote command exits non-zero. Returns the remote command's exit code.
_run_direct() {
local alias="$1" remote_cmd="$2"
require_sshpass
local addr_port; addr_port=$(read_host_addr "$alias")
[ -n "$addr_port" ] || die "no such alias: $alias"
local addr port
addr=$(printf '%s' "$addr_port" | cut -f1)
port=$(printf '%s' "$addr_port" | cut -f2)
local credfile; credfile=$(_direct_creds "$alias") \
|| die "no password set for $alias — run 'pass $alias' first (direct mode needs the stored credential per command)"
local errfile; errfile=$(mktemp 2>/dev/null || echo "/tmp/larry-ssh-direct.err.$$")
# NO ControlMaster/ControlPath. Forced password method so sshpass feeds the
# password cleanly past any pre-auth banner (same rationale as the master
# path's v0.8.15 PreferredAuthentications=password hardening). BatchMode is
# NOT set — sshpass supplies the password non-interactively via the askpass
# file descriptor; BatchMode would suppress that path on some builds.
sshpass -f "$credfile" ssh \
-o "PreferredAuthentications=password" \
-o "PubkeyAuthentication=no" \
-o "NumberOfPasswordPrompts=1" \
-o "StrictHostKeyChecking=accept-new" \
-o "ControlMaster=no" \
-o "ControlPath=none" \
-o "ConnectTimeout=$_DIRECT_CONNECT_TIMEOUT" \
-p "$port" \
"$addr" "$remote_cmd" 2>"$errfile"
local rc=$?
# On a real failure, surface the FILTERED stderr (banner + sudo noise removed)
# so the operator sees the genuine reason without the boilerplate. On success,
# the benign noise is simply dropped — stdout is already the clean result.
if [ "$rc" -ne 0 ]; then
local filtered; filtered=$(_filter_direct_stderr < "$errfile")
if [ -n "$filtered" ]; then
printf 'ssh-helper: direct command failed for %s (rc=%d). Remote stderr (benign banner/sudo lines stripped):\n' "$alias" "$rc" >&2
printf '%s\n' "$filtered" >&2
else
printf 'ssh-helper: direct command failed for %s (rc=%d) with no non-benign stderr — likely an auth failure (stale/rotated password?) or a connection reset. Re-check: ssh-helper.sh setup %s\n' "$alias" "$rc" "$alias" >&2
fi
fi
rm -f "$errfile"
return "$rc"
}
# _direct_scp ALIAS SRC DST → scp SRC→DST over a FRESH sshpass connection (no
# ControlMaster), forced password auth, host-key checked. Either SRC or DST is a
# remote spec of the form "<addr>:<path>" supplied by the caller (cmd_pull builds
# it). Returns scp's exit code. STDERR (incl. banner/sudo noise) is filtered the
# same way as _run_direct and surfaced only on failure. v0.8.17.
_direct_scp() {
local alias="$1" src="$2" dst="$3"
require_sshpass
local addr_port; addr_port=$(read_host_addr "$alias")
[ -n "$addr_port" ] || die "no such alias: $alias"
local port; port=$(printf '%s' "$addr_port" | cut -f2)
local credfile; credfile=$(_direct_creds "$alias") \
|| die "no password set for $alias — run 'pass $alias' first"
local errfile; errfile=$(mktemp 2>/dev/null || echo "/tmp/larry-scp-direct.err.$$")
sshpass -f "$credfile" scp -q \
-o "PreferredAuthentications=password" \
-o "PubkeyAuthentication=no" \
-o "NumberOfPasswordPrompts=1" \
-o "StrictHostKeyChecking=accept-new" \
-o "ControlMaster=no" \
-o "ControlPath=none" \
-o "ConnectTimeout=$_DIRECT_CONNECT_TIMEOUT" \
-P "$port" \
"$src" "$dst" 2>"$errfile"
local rc=$?
if [ "$rc" -ne 0 ]; then
local filtered; filtered=$(_filter_direct_stderr < "$errfile")
printf 'ssh-helper: direct scp failed for %s (rc=%d):\n' "$alias" "$rc" >&2
[ -n "$filtered" ] && printf '%s\n' "$filtered" >&2
fi
rm -f "$errfile"
return "$rc"
}
# _dispatch_remote ALIAS RAW_CMD → run RAW_CMD on ALIAS, choosing the transport:
# DIRECT mode (column 5 == on) → fresh per-command sshpass (_run_direct)
# else → existing ControlMaster multiplex
# In BOTH cases the remote command is shaped identically by _remote_cmd_for, so
# the HCIROOT pin and login-shell semantics are unchanged across transports.
# Requires (master mode only) that the master is open — the master-mode branch
# preserves the prior die-on-closed-master behaviour exactly.
_dispatch_remote() {
local alias="$1" raw="$2"
local shaped; shaped=$(_remote_cmd_for "$alias" "$raw")
if _alias_is_direct "$alias"; then
_run_direct "$alias" "$shaped"
return $?
fi
# ── ControlMaster path (unchanged for non-direct aliases) ────────────────
local addr_port; addr_port=$(read_host_addr "$alias")
[ -n "$addr_port" ] || die "no such alias: $alias"
local addr port
@ -447,11 +715,25 @@ cmd_exec() {
if [ ! -S "$sock" ] || ! ssh -S "$sock" -O check -p "$port" "$addr" 2>/dev/null; then
die "no open master for $alias — run 'setup $alias' first"
fi
# Multiplexed; no password needed. If the alias has a pinned HCIROOT we export
# it explicitly and skip the login profile (v0.8.15 sudo-gated-profile fix);
# otherwise we run in a login shell so $HCIROOT et al. populate from the remote
# Cloverleaf login profile (see _build_login_cmd / _remote_cmd_for).
ssh -S "$sock" -p "$port" -o BatchMode=yes "$addr" "$(_remote_cmd_for "$alias" "$cmd")"
ssh -S "$sock" -p "$port" -o BatchMode=yes "$addr" "$shaped"
}
cmd_exec() {
local alias="${1:-}"
[ -n "$alias" ] || die "usage: exec <alias> <command...>"
shift
local cmd="$*"
[ -n "$cmd" ] || die "no command given"
local addr_port; addr_port=$(read_host_addr "$alias")
[ -n "$addr_port" ] || die "no such alias: $alias"
# v0.8.17: transport selection is centralised in _dispatch_remote.
# • DIRECT mode → a fresh per-command sshpass connection (no master), with
# benign banner/sudo stderr stripped and real errors surfaced on failure.
# • else → the existing ControlMaster multiplex (no password needed).
# In both cases the remote command is shaped identically: a pinned HCIROOT is
# exported explicitly + login profile skipped (v0.8.15); otherwise a login
# shell populates $HCIROOT et al. (see _remote_cmd_for / _build_login_cmd).
_dispatch_remote "$alias" "$cmd"
}
# cmd_discover ALIAS — proactively detect the remote Cloverleaf environment.
@ -471,10 +753,15 @@ cmd_discover() {
local addr port
addr=$(printf '%s' "$addr_port" | cut -f1)
port=$(printf '%s' "$addr_port" | cut -f2)
# v0.8.17: in DIRECT mode there is no master to check — _dispatch_remote runs a
# fresh per-command sshpass connection below. Only validate an open master for
# the (unchanged) multiplex path.
if ! _alias_is_direct "$alias"; then
local sock="$SSH_SOCKETS_DIR/$alias.sock"
if [ ! -S "$sock" ] || ! ssh -S "$sock" -O check -p "$port" "$addr" 2>/dev/null; then
die "no open master for $alias — run 'setup $alias' first"
fi
fi
# A single remote script. It:
# - prints HCIROOT\t$HCIROOT
@ -547,7 +834,11 @@ $s"; fi;
dropped=$(printf "%s" "$dropped" | sed "s/^ *//");
[ -n "$dropped" ] && printf "EXCLUDED\t%s\n" "$dropped";
printf "%s\n" "$kept" | while IFS= read -r s; do [ -n "$s" ] && printf "SITE\t%s\n" "$s"; done'
ssh -S "$sock" -p "$port" -o BatchMode=yes "$addr" "$(_remote_cmd_for "$alias" "$remote")"
# v0.8.17: dispatch over DIRECT sshpass or the ControlMaster, per the alias's
# flag. The TSV that the tool layer parses is on STDOUT and stays clean; the
# qa banner/sudo noise on STDERR is stripped by _run_direct's filter (direct
# mode) and surfaced only on a real non-zero failure.
_dispatch_remote "$alias" "$remote"
}
# ── v0.6.8: scp helpers that multiplex via the existing ControlMaster ────────
@ -594,6 +885,34 @@ _pull_cache_path() {
cmd_pull() {
local alias="${1:-}" remote="${2:-}" local_path="${3:-}"
[ -n "$alias" ] && [ -n "$remote" ] || die "usage: pull <alias> <remote_path> [local_path]"
# v0.8.17: DIRECT mode — no ControlMaster. The remote-size probe rides a fresh
# per-command sshpass connection (_dispatch_remote → _run_direct), and the
# transfer uses _direct_scp (also fresh sshpass). Everything else (cache path,
# size verification, the clean final-line local path) is identical.
if _alias_is_direct "$alias"; then
local addr_port; addr_port=$(read_host_addr "$alias")
[ -n "$addr_port" ] || die "no such alias: $alias"
local _d_addr; _d_addr=$(printf '%s' "$addr_port" | cut -f1)
[ -z "$local_path" ] && local_path=$(_pull_cache_path "$alias" "$remote")
mkdir -p "$(dirname "$local_path")" 2>/dev/null
local remote_size
remote_size=$(coerce_int "$(_dispatch_remote "$alias" "wc -c < $(printf '%q' "$remote") 2>/dev/null" 2>/dev/null)" "")
if [ -z "$remote_size" ] || ! [[ "$remote_size" =~ ^[0-9]+$ ]]; then
die "remote file not found or not readable: $remote"
fi
if _direct_scp "$alias" "$_d_addr:$remote" "$local_path"; then
local got; got=$(coerce_int "$(wc -c < "$local_path" 2>/dev/null)" 0)
if [ "$got" != "$remote_size" ]; then
die "partial transfer: remote=$remote_size bytes, local=$got bytes ($local_path)"
fi
ok "pulled $alias:$remote$local_path ($got bytes, direct)"
printf '%s\n' "$local_path"
return 0
fi
return 1
fi
_resolve_open_master "$alias"
[ -z "$local_path" ] && local_path=$(_pull_cache_path "$alias" "$remote")
mkdir -p "$(dirname "$local_path")" 2>/dev/null
@ -687,7 +1006,13 @@ cmd_pull_smat() {
local alias="${1:-}" site="${2:-}" thread="${3:-}" days_back="${4:-}"
[ -n "$alias" ] && [ -n "$site" ] && [ -n "$thread" ] \
|| die "usage: pull-smat <alias> <site> <thread> [days_back]"
# v0.8.17: in DIRECT mode every remote op is a fresh per-command sshpass
# connection — there is no master to resolve. Only require an open master for
# the (unchanged) multiplex path; both the find/sample command dispatches and
# the full-file scp below pick the transport via the direct flag.
if ! _alias_is_direct "$alias"; then
_resolve_open_master "$alias"
fi
# Discover the remote .smatdb path. $HCISITEDIR/$HCIROOT are resolved by the
# LOGIN shell (see _build_login_cmd) — the v0.8.13 fix — so we no longer
@ -711,7 +1036,11 @@ cmd_pull_smat() {
local _smat_raw remote_smatdb
# v0.8.15: honour a pinned HCIROOT (explicit export, no sudo-gated login profile).
_smat_raw=$(ssh -S "$_RH_SOCK" -p "$_RH_PORT" -o BatchMode=yes "$_RH_ADDR" "$(_remote_cmd_for "$alias" "$find_cmd")" 2>&1)
# v0.8.17: dispatch over DIRECT sshpass or the ControlMaster per the alias flag.
# We capture stdout+stderr together (2>&1) as before — the SMATDB_PATH sentinel
# / ERROR: parsing already tolerates banner/sudo noise interleaved on stderr,
# so the direct path needs no extra filtering here.
_smat_raw=$(_dispatch_remote "$alias" "$find_cmd" 2>&1)
remote_smatdb=$(printf '%s\n' "$_smat_raw" | grep '^SMATDB_PATH:' | tail -1)
if [ -n "$remote_smatdb" ]; then
remote_smatdb="${remote_smatdb#SMATDB_PATH:}"
@ -769,7 +1098,8 @@ cmd_pull_smat() {
# and skip the sudo-gated login profile (v0.8.15). Note: when pinned, sqlite3
# must be resolvable on the default non-login PATH; if it is not, the
# sample_cmd already emits a clear "ERROR: sqlite3 not on remote PATH".
ssh -S "$_RH_SOCK" -p "$_RH_PORT" -o BatchMode=yes "$_RH_ADDR" "$(_remote_cmd_for "$alias" "$sample_cmd")"
# v0.8.17: dispatch over DIRECT sshpass or the ControlMaster per the alias flag.
_dispatch_remote "$alias" "$sample_cmd"
}
case "${1:-help}" in
@ -778,6 +1108,7 @@ case "${1:-help}" in
remove|rm) shift; cmd_remove "$@" ;;
pass|passwd) shift; cmd_pass "$@" ;;
set-hciroot|hciroot) shift; cmd_set_hciroot "$@" ;;
set-direct|direct) shift; cmd_set_direct "$@" ;;
setup|open) shift; cmd_setup "$@" ;;
close|exit) shift; cmd_close "$@" ;;
status) shift; cmd_status "$@" ;;