Skip to content

Commit 6aab926

Browse files
fix(watcher): escape exception strings to prevent rich MarkupError crashes
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> Co-authored-by: shenald-dev <245350826+shenald-dev@users.noreply.github.com>
1 parent 7b049fb commit 6aab926

2 files changed

Lines changed: 23 additions & 1 deletion

File tree

src/echo/watcher.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ def _run_command(self, event_path):
161161
else:
162162
console.print(f"[red]✖ Command failed with exit code {process.returncode}.[/red]")
163163
except Exception as e:
164-
console.print(f"[bold red]Error executing command: {e}[/bold red]")
164+
console.print(f"[bold red]Error executing command: {escape(str(e))}[/bold red]")
165165

166166
def _is_ignored_impl(self, path: str) -> bool:
167167
if path.startswith(self._abs_base_path):

tests/test_markup.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import time
22
from echo.watcher import CommandRunnerHandler
3+
import subprocess
4+
35
from unittest.mock import MagicMock
46

57
def test_rich_markup_crash_escaping():
@@ -24,3 +26,23 @@ def test_rich_markup_crash_escaping():
2426
if handler.current_process:
2527
handler.current_process.terminate()
2628
handler.current_process.wait()
29+
30+
31+
def test_rich_error_crash():
32+
handler = CommandRunnerHandler("echo test")
33+
34+
class MockException(Exception):
35+
def __str__(self):
36+
return "File not found: [missing.py]"
37+
38+
original_popen = subprocess.Popen
39+
40+
def fake_popen(*args, **kwargs):
41+
raise MockException()
42+
43+
subprocess.Popen = fake_popen
44+
try:
45+
# this should crash rich with MarkupError if not escaped
46+
handler._run_command("test.txt")
47+
finally:
48+
subprocess.Popen = original_popen

0 commit comments

Comments
 (0)