Repository navigation
fix(bot-relay): delivery works on Windows paths and PATH-less gateways (#93590, salvage #93601, credit #93597) - #93658
Merged
Merged
Conversation
…ry ENOENT Two failures on a Windows desktop install relaying to a remote gateway (#93590): 1. waiter_command embeds the reply path in generated python -c source with !r. repr escapes each backslash, but the Windows execution layer folds \\ back to \, so \U in C:\Users\... parses as a unicode escape and SyntaxErrors the whole waiter script. Raw-string literals keep the folded single backslash a literal; POSIX paths have no backslashes so the prefix is a no-op there, and \' inside a raw literal still cannot terminate the string, keeping the #93091 injection defense intact. 2. local_delivery_command hardcoded "hermes", relying on PATH — absent in service contexts (systemd units, desktop launchers, non-login SSH shells), so delivery died with ENOENT. It now resolves the CLI next to this gateway's own interpreter (venv bin/Scripts sibling, hermes.exe on Windows) with a bare-name fallback. The #93091 per-profile turn-lock recognition in bot_mode_dm now matches the CLI element by basename (split on both separators) so resolved absolute paths still take the lock instead of silently bypassing it. Fixes #93590
CI runners have a real hermes sibling next to the venv python, so local_delivery_command now resolves an absolute path there — the exact argv filters in the retry-policy fakes and the relay-methods pins must match by basename instead of the literal "hermes", mirroring the _delivery_lock matcher.
… decoding on delivery subprocess Salvage hardening on top of #93601 (with #93597 covering the same core mechanisms) for #93590: - _hermes_cli(): after the venv-sibling check (hermes.exe on win32), try shutil.which('hermes') before the bare-name fallback, so environments with a PATH but no venv sibling resolve exactly what an interactive shell would. Platform test switched os.name -> sys.platform ('win32') per repo convention. - tui_gateway/methods_bot_relay.py deliver: pin encoding='utf-8', errors='replace' on both subprocess.run sites — without them the child's UTF-8 output is decoded with the locale codec (cp1252/GBK on Windows), mangling non-ASCII replies or raising on undecodable bytes. - Regression tests: shutil.which resolution step, bare-name fallback with which=None, and encoding-pin assertions in the deliver transport test. Refs #93590, #93597, #93601
This was referenced Aug 24, 2026
6 tasks done
12 of 13 tasks
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.
Summary
bot_relay delivery works on Windows and in PATH-less service contexts: the generated waiter script no longer dies with a SyntaxError when the reply path contains
\U...(MSYS backslash folding), and the delivery command no longer fails with "hermes not found" when the venv isn't on PATH. Fixes #93590.Changes
tools/bot_relay.py: raw-string prefixes on BOTH injected literals (reply path and label) in the waiter script — no-op on POSIX, survives Git-Bash arg conversion on Windows; injection defense from Bot Mode reliability program: typed failure reasons, envelope TTL, attention badges, leader-routed group rooms, retry session policy #93091 preserved (basename-matched turn-lock)tools/bot_relay.py: delivery CLI resolvesPath(sys.executable).parent / hermes(.exe)→shutil.which→ bare fallback, on all platforms (the ENOENT also reproduces on Linux systemd gateways)tui_gateway/methods_bot_relay.py:encoding='utf-8', errors='replace'pinned on both subprocess.run sites (cp1252/GBK mangling)Validation
C:\Users\测试pathCredit: @jdtimothy first (#93597, earliest — identified both mechanisms), salvaged on @liuhao1024's more complete #93601 (authorship preserved on both commits); utf-8 pin + which-step added on top.
Infographic