Skip to content

fix(shell): drop POSIX quote-wrap in _shell_escape; strip CR in safe_eval (#84)#85

Merged
fdaviddpt merged 2 commits into
mainfrom
fix/84-safe-eval-crlf-and-quote-unwrap
May 27, 2026
Merged

fix(shell): drop POSIX quote-wrap in _shell_escape; strip CR in safe_eval (#84)#85
fdaviddpt merged 2 commits into
mainfrom
fix/84-safe-eval-crlf-and-quote-unwrap

Conversation

@fdaviddpt
Copy link
Copy Markdown
Contributor

Summary

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 → 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:126 extract
  • save-session.sh:183 parse-haiku
  • save-session.sh:246 parse-haiku (NDC)
  • run-consolidation.sh:74 consolidate

Plus: pre-fix log.sh:safe_eval did not strip CR. Python on Windows emits \r\n, so values kept a trailing \r, breaking integer tests in save-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-redundant safe_eval override (single source of truth in log.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:

  1. The CRLF tests in test_path_resolution.py sourced only detect-tools.sh — the file that had the CR strip — never log.sh's broken copy that real orchestrators reach.
  2. No end-to-end test of save-session.sh (the script with the shadowing source order).
  3. No seam roundtrip between _shell_escape and safe_eval. Both sides tested in isolation; the contract between them was never asserted.

The new test_shell_escape_safe_eval_roundtrip closes that hole.

Test plan

  • pytest — 391 passed, 1 skipped, 99% coverage locally.
  • New seam tests fail red against main, pass green after fix.
  • CI green on ubuntu/macos/windows matrix.

Fixes #84

Florian DAVID 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>
@fdaviddpt fdaviddpt merged commit c2c82ab into main May 27, 2026
12 checks passed
@fdaviddpt fdaviddpt deleted the fix/84-safe-eval-crlf-and-quote-unwrap branch May 27, 2026 12:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Auto-save pipeline broken on Windows/Git Bash: CRLF + single-quote path wrapping in safe_eval

1 participant