fix: 1.2.1 follow-ups — /ss quoting (#43), channel-relay uid (#48), attach exit-5 (#47) - #53
Merged
Merged
Conversation
…ttach exit-5 (#47) Three bugs surfaced exercising 1.2.0 in real daemon/sandy-ui use. #43 /ss quoting — the generated /ss commands spliced $ARGUMENTS (claude) and {{args}} (gemini) directly into the `!`…`` / `!{ }` shell-exec line, so a quoted request (`/ss 2 "what's this?"`) broke the shell parse and was a latent injection vector. The shell line now runs a FIXED `sandy-ss-paths 5` with no user text; the count is handled in model prose (read the first N of the newest 5, default 1). codex SKILL.md was already prose-only — unchanged. #48 channel-relay uid — the host-side relay execs `tmux has-session`/`send-keys` via `docker exec` WITHOUT `-u "$(id -u)"`. docker exec defaults to the image user (root — sandy sets no USER), but the in-container tmux server runs as the gosu-dropped host uid, so its socket is at /tmp/tmux-<uid>/. Root can't see it, so the gemini/codex/opencode host-side Telegram/Discord relay silently never delivered. Same class as the daemon-probe -u fixes. Claude channels use an in-container plugin and were unaffected. #47 attach exit-5 (completes the exit-5 half; the zombie half shipped in 5048899) — post-attach, a container-still-up-but-session-gone state (the agent exited while a client was attached and the supervisor watch-loop is mid- teardown) was misclassified as "attach failed" (exit 5). It's a normal session-end → now exit 0, so sandy-ui stops sticky-reconnecting a dying session. A one-shot re-probe absorbs a transient docker-exec hiccup before the 0 verdict. Exit 5 is now reserved for a failure to *establish* the attach. Regression guards: run-tests.sh §45j (no user-arg splice in the /ss shell lines) + new §46 (channel-relay execs are uid-scoped, no bare-root exec remains). Docs synced: SPECIFICATION relay-inject example shows -u and why; CLAUDE.md DEC-C clarifies post-attach exit-5 is establishment-only. templates/user-setup.sh.tmpl regenerated (no drift). Closes #43 Closes #48 Closes #47 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Three bugs surfaced exercising 1.2.0 in real daemon / sandy-ui use.
#43 — /ss quoting
The generated
/sscommands spliced$ARGUMENTS(claude) and{{args}}(gemini) directly into the!`…`/!{ }shell-exec line, so a quoted request like/ss 2 "what's this?"broke the shell parse (and was a latent injection vector). The shell line now runs a fixedsandy-ss-paths 5with zero user text; the count is handled in model prose (read the first N of the newest 5, default 1). codexSKILL.mdwas already prose-only — unchanged.#48 — channel-relay uid
The host-side relay execs
tmux has-session/send-keysviadocker execwithout-u "$(id -u)".docker execdefaults to the image user (root — sandy sets noUSER), but the in-container tmux server runs as the gosu-dropped host uid, so its socket is at/tmp/tmux-<uid>/. Root can't see it → the gemini/codex/opencode host-side Telegram/Discord relay silently never delivered. Same class as the daemon-probe-ufixes. Claude channels (in-container plugin) were unaffected.#47 — attach exit-5 (completes the exit-5 half; zombie half shipped in
5048899)Post-attach, a container-still-up-but-session-gone state (the agent exited while a client was attached and the supervisor watch-loop is mid-teardown) was misclassified as "attach failed" (exit 5). It's a normal session-end → now exit 0, so sandy-ui stops sticky-reconnecting a dying session. A one-shot re-probe absorbs a transient
docker exechiccup before the 0 verdict. Exit 5 is now reserved for a failure to establish the attach.Tests / docs
run-tests.sh§45j (no user-arg splice in the/ssshell lines) + new §46 (channel-relay execs are uid-scoped, no bare-root exec remains).SPECIFICATION.mdrelay-inject example shows-u+ why;CLAUDE.mdDEC-C clarifies post-attach exit-5 is establishment-only.templates/user-setup.sh.tmplregenerated (no drift).Closes #43
Closes #48
Closes #47
🤖 Generated with Claude Code