v0.8.16: hotfix set -u unbound-variable abort in /ssh-set-hciroot + /ssh REPL slash handlers
Single-line `local a=… b="…$a…"` referenced the 1st var before it was bound within the SAME `local` statement, aborting under set -u on Cygwin/MobaXterm (and modern bash). Split larry.sh:6903 (/ssh-set-hciroot) and the same latent pattern at larry.sh:6925 (/ssh) into set-u-safe declare-then-assign form. Codebase-wide bug-class audit (larry.sh + all lib/*.sh + scripts): zero remaining instances. Closed the v0.8.15 gate gap by driving the ACTUAL REPL slash-dispatch handler bodies under set -u + BASH_COMPAT=3.2 (not just the ssh-helper subcommand): /ssh-set-hciroot normal + empty-path-clear, /ssh, and usage paths all pass; old code aborts under the same harness. No-traffic-bypass line unchanged. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
fc667e2451
commit
0e6495223a
47
CHANGELOG.md
47
CHANGELOG.md
@ -4,6 +4,53 @@ 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.16 — 2026-05-28
|
||||
|
||||
Hotfix (Clover): `set -u` unbound-variable abort in the v0.8.15
|
||||
`/ssh-set-hciroot` REPL slash command, reported live on Bryan's MobaXterm /
|
||||
Cygwin bash (`larry.sh: line 6903: _sh_alias: unbound variable`).
|
||||
|
||||
**Root cause.** `larry.sh:6903` was a single-line `local` declaration in which
|
||||
the 2nd variable's initializer referenced the 1st variable assigned in the SAME
|
||||
`local` statement:
|
||||
`local _sh_alias="${rest%% *}" _sh_path="${rest#"$_sh_alias"}"`.
|
||||
Under `set -u`, `$_sh_alias` is treated as unbound at expansion time within its
|
||||
own `local` statement, aborting the command. This is NOT Cygwin/bash-3.2
|
||||
specific — it reproduces identically on bash 5.x. The same latent pattern lived
|
||||
at `larry.sh:6925` (the `/ssh <alias> <cmd>` handler:
|
||||
`local alias="${rest%% *}" rcmd="${rest#"$alias"}"`), not yet triggered only
|
||||
because that path hadn't been run.
|
||||
|
||||
**Fix.** Both split into set-u-safe form — declare the locals first, assign the
|
||||
first, THEN reference it on a later line. Correct on every bash version.
|
||||
|
||||
1. `/ssh-set-hciroot` handler (was `larry.sh:6903`) — safe-split; preserves the
|
||||
empty-path "clear the pin" semantics.
|
||||
2. `/ssh` handler (was `larry.sh:6925`) — same safe-split.
|
||||
|
||||
**Codebase-wide bug-class audit.** Every `.sh` (larry.sh + all `lib/*.sh` +
|
||||
top-level scripts) was scanned for any single-statement `local`/`declare`/
|
||||
`typeset`/`readonly`/`export` where one variable's initializer references
|
||||
another variable assigned in the SAME statement. After the two fixes above,
|
||||
**zero remaining instances**. All superficially-similar lines elsewhere are
|
||||
`;`-separated sequential statements (e.g. `_x="${rest%% *}"; rest="${rest#"$_x"}"`)
|
||||
where the referenced variable is already bound — these are the CORRECT idiom and
|
||||
are safe under `set -u`.
|
||||
|
||||
**Gate-gap closed.** The v0.8.15 gate exercised the `ssh-helper.sh set-hciroot`
|
||||
SUBCOMMAND but never the larry.sh `/ssh-set-hciroot` REPL slash dispatch — where
|
||||
the bug actually was. The v0.8.16 gate drives the ACTUAL slash-command handler
|
||||
bodies (extracted verbatim from the fixed source) through a `case` dispatcher
|
||||
under `set -u` with `BASH_COMPAT=3.2`, non-interactively, with no self-update /
|
||||
API / bootstrap. Verified `/ssh-set-hciroot <alias> <path>` (normal),
|
||||
`/ssh-set-hciroot <alias>` (empty-path CLEAR), trailing-space clear, no-args
|
||||
usage, `/ssh <alias> <cmd>`, and `/ssh <alias>` (usage) all execute WITHOUT the
|
||||
unbound-var abort. The same harness run against the OLD v0.8.15 line aborts with
|
||||
`_sh_alias: unbound variable` (rc=1), confirming the gate now catches this
|
||||
regression class. The no-traffic-bypass security line is unchanged.
|
||||
|
||||
---
|
||||
|
||||
## v0.8.15 — 2026-05-28
|
||||
|
||||
Legacy/qa remote-enumeration fix (Clover). Three confirmed-live properties of
|
||||
|
||||
6
MANIFEST
6
MANIFEST
@ -23,16 +23,16 @@
|
||||
# scripts/make-manifest.sh and bump VERSION.
|
||||
|
||||
# Top-level scripts
|
||||
larry.sh 2e7650eb7a014624bd6956c30ce3a54e0e87d4ccfc73bb0b2ae82d1a31b882e0
|
||||
larry.sh 7bbd920f7a29379aadad3e59a298ff416333e9299241db7c7bb8c42cc7750f9d
|
||||
larry-tunnel.sh 6b050e4eeab15669f4858eaf3b807f168f211ced07815db9521bc40a093f6aaa
|
||||
larry-auth.sh a220cdf7878569dc3028951ee57fc8d5e706a8ca5c6aa45347b58facb386f831
|
||||
larry-rollback.sh 91b5e9aa6c79266bf306dcfba4ca791c07971bd6924d67a779037531648aa6d0
|
||||
install-larry.sh e97da4e12a0d8863ca18d79b12f6c4294c72fa6d4b11dffeab66504236bb4eb1
|
||||
|
||||
# Metadata
|
||||
VERSION 8517de55d0fc1041caab07518dbf7da86dba47c3befe0a6ef84d005872cb799d
|
||||
VERSION 088faf7f331988e309c37e27272af81cd41fdcf4466022059ffdd3184e3c7d34
|
||||
MANUAL.md 666128a086b59ff3c31a574aec0c5dd681666d66319da9f078451bf9013ca5e1
|
||||
CHANGELOG.md 0b8f2dba750577f934935dd7d5805c498afa9d516cd37e5b6cda039cb86ec350
|
||||
CHANGELOG.md 3db03a7913b3a66310f9cb282eaa6c3554d5ed59ef92eca78ef02257dc97277f
|
||||
|
||||
# Agent personas (system-prompt overlays)
|
||||
agents/larry.md 11ea905fa7cac6fa7baeb11b2d62af07b15a666ce90cfe36491bcbc555244397
|
||||
|
||||
18
larry.sh
18
larry.sh
@ -78,7 +78,7 @@ set -o pipefail
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# Config
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
LARRY_VERSION="0.8.15"
|
||||
LARRY_VERSION="0.8.16"
|
||||
LARRY_HOME="${LARRY_HOME:-$HOME/.larry}"
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
@ -6900,8 +6900,13 @@ main_loop() {
|
||||
if [ -z "$rest" ]; then
|
||||
err "usage: /ssh-set-hciroot <alias> <path> (empty path clears the pin)"; continue
|
||||
fi
|
||||
local _sh_alias="${rest%% *}" _sh_path="${rest#"$_sh_alias"}"
|
||||
_sh_path="${_sh_path# }"
|
||||
# v0.8.16: set-u-safe split. A single-line `local a=… b="…$a…"`
|
||||
# references $_sh_alias before it is bound within the SAME `local`
|
||||
# statement, which aborts under `set -u` on bash 3.2/Cygwin
|
||||
# (MobaXterm) AND modern bash. Declare first, assign sequentially.
|
||||
local _sh_alias _sh_path
|
||||
_sh_alias="${rest%% *}"
|
||||
_sh_path="${rest#"$_sh_alias"}"; _sh_path="${_sh_path# }"
|
||||
if [ -z "$_sh_alias" ]; then
|
||||
err "usage: /ssh-set-hciroot <alias> <path>"; continue
|
||||
fi
|
||||
@ -6922,8 +6927,11 @@ main_loop() {
|
||||
continue ;;
|
||||
/ssh*) local rest; rest=$(_slash_args "/ssh" "$input")
|
||||
if [ -z "$rest" ]; then err "usage: /ssh <alias> <command>"; continue; fi
|
||||
local alias="${rest%% *}" rcmd="${rest#"$alias"}"
|
||||
rcmd="${rcmd# }"
|
||||
# v0.8.16: same set-u-safe split as /ssh-set-hciroot above —
|
||||
# $alias was referenced before binding in a single-line `local`.
|
||||
local alias rcmd
|
||||
alias="${rest%% *}"
|
||||
rcmd="${rest#"$alias"}"; rcmd="${rcmd# }"
|
||||
if [ -z "$alias" ] || [ -z "$rcmd" ]; then
|
||||
err "usage: /ssh <alias> <command>"; continue
|
||||
fi
|
||||
|
||||
Loading…
Reference in New Issue
Block a user