fix(shell): drop POSIX quote-wrap in _shell_escape; strip CR in safe_eval (#84)#85
Merged
Merged
Conversation
added 2 commits
May 27, 2026 14:05
…eval (#84) The shell↔Python variable bridge had two mismatched halves: - pipeline.shell._shell_escape single-quote-wrapped values per POSIX `eval` convention. - scripts/log.sh safe_eval assigned verbatim via `printf -v` — no shell expansion, so wrapping quotes survived into the variable. Invisible on Linux (temp paths contain no shell-unsafe chars, so the escaper returned them unquoted). Broken on Windows: backslash paths got quoted, then stored with literal quotes, then handed to Python's `open()` which failed with `OSError: [Errno 22]`. Fix on the Python side: emit values verbatim (validate no newline). The parser was always verbatim — now the emitter matches. Also strip CR in safe_eval to handle Python's `\r\n` line endings on Windows. Removed the now-redundant safe_eval override from detect-tools.sh; log.sh is the single source of truth. Adds tests/test_safe_eval_seam.py pinning the contract both halves must satisfy, including a parametrized roundtrip across Linux/Windows paths, spaces, and quotes. Fixes #84 Co-Authored-By: Max <noreply>
- Bump plugin.json + README badge to 0.7.3 - Add CHANGELOG entry crediting reporter - Stale-docstring cleanup in detect-tools.sh and test_safe_eval_seam.py (referenced the pre-fix POSIX single-quote-wrap behavior) Co-Authored-By: Max <noreply>
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
The shell↔Python variable bridge had two mismatched halves:
pipeline.shell._shell_escapesingle-quote-wrapped values per POSIXevalconvention.scripts/log.sh:safe_evalassigned verbatim viaprintf -v— no shell expansion, so wrapping quotes survived into the variable.Invisible on Linux (temp paths contain no shell-unsafe chars, so the escaper returned them unquoted). Broken on Windows: backslash paths got quoted → stored with literal quotes →
open('C:\\...txt')actually received"'C:\\...txt'"→OSError: [Errno 22].Bridge call sites (all hit the same bug):
save-session.sh:126extractsave-session.sh:183parse-haikusave-session.sh:246parse-haiku (NDC)run-consolidation.sh:74consolidatePlus: pre-fix
log.sh:safe_evaldid not strip CR. Python on Windows emits\r\n, so values kept a trailing\r, breaking integer tests insave-session.sh.Changes
pipeline/shell.py:_shell_escape→ emit verbatim, raise on newline. The parser was always verbatim — now the emitter matches.scripts/log.sh:safe_eval→ strip trailing\r(Windows CRLF).scripts/detect-tools.sh→ drop the now-redundantsafe_evaloverride (single source of truth inlog.sh).tests/test_safe_eval_seam.py(new) → pin the contract both halves must satisfy, including a parametrized Python↔bash roundtrip across Linux paths, Windows backslash paths, spaces, single quotes, and trivial values.tests/test_shell.py,tests/test_path_resolution.py→ updated to match the new contract.Why missed by CI
Windows CI matrix exists (
ubuntu-latest/macos-latest/windows-latest) but was blind:test_path_resolution.pysourced onlydetect-tools.sh— the file that had the CR strip — neverlog.sh's broken copy that real orchestrators reach.save-session.sh(the script with the shadowing source order)._shell_escapeandsafe_eval. Both sides tested in isolation; the contract between them was never asserted.The new
test_shell_escape_safe_eval_roundtripcloses that hole.Test plan
pytest— 391 passed, 1 skipped, 99% coverage locally.main, pass green after fix.Fixes #84