From e79f170d30da6b97363ed8e25dd9d2ec593da57e Mon Sep 17 00:00:00 2001 From: zerone0x <39543393+zerone0x@users.noreply.github.com> Date: Tue, 14 Jul 2026 20:04:07 +0000 Subject: [PATCH] fix: reject malformed brace globs Fixes #1690 Co-Authored-By: OpenAI Codex --- CHANGELOG.md | 1 + src/serena/util/text_utils.py | 12 ++++++++---- test/serena/test_text_utils.py | 15 +++++++++++++++ 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a67618fb..edeb6bcd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,7 @@ Status of the `main` branch. Changes prior to the next official version change w - Fix: Use LSP-compliant line splitting ("\n", "\r\n" and "\r" can define line breaks); previously only "\n" considered - Fix: Apply consistent line splitting across tools, uniformly applying the LSP splitting semantics; affects `search_text` used by `search_for_pattern` tool (reported in #1684) + - Fix: glob pattern expansion in `expand_braces` did not terminate with empty or unbalanced braces #1690 * CLI: - Fix `--project-from-cwd` hijacking git worktrees nested under a Serena project. `find_project_root` diff --git a/src/serena/util/text_utils.py b/src/serena/util/text_utils.py index 8deb9856..e9aebf76 100644 --- a/src/serena/util/text_utils.py +++ b/src/serena/util/text_utils.py @@ -216,18 +216,22 @@ def expand_braces(pattern: str) -> list[str]: Handles multiple brace sets as well. """ patterns = [pattern] - while any("{" in p for p in patterns): + while any("{" in p or "}" in p for p in patterns): new_patterns = [] for p in patterns: - match = re.search(r"\{([^{}]+)\}", p) + match = re.search(r"\{([^{}]*)\}", p) if match: + options_expr = match.group(1) + if not options_expr: + raise ValueError(f"Invalid glob brace expression in {pattern!r}: empty braces are not allowed") + prefix = p[: match.start()] suffix = p[match.end() :] - options = match.group(1).split(",") + options = options_expr.split(",") for option in options: new_patterns.append(f"{prefix}{option}{suffix}") else: - new_patterns.append(p) + raise ValueError(f"Invalid glob brace expression in {pattern!r}: unmatched brace") patterns = new_patterns return patterns diff --git a/test/serena/test_text_utils.py b/test/serena/test_text_utils.py index 936779fc..ce63450d 100644 --- a/test/serena/test_text_utils.py +++ b/test/serena/test_text_utils.py @@ -606,6 +606,21 @@ class TestExpandBraces: assert sorted(expand_braces(pattern)) == sorted(expected) + @pytest.mark.parametrize( + "pattern", + [ + "src/{}.py", + "src/{utils,models", + "src/utils,models}.py", + ], + ) + def test_expand_braces_rejects_malformed_braces(self, pattern): + """Malformed brace globs should fail instead of looping forever.""" + from serena.util.text_utils import expand_braces + + with pytest.raises(ValueError, match="Invalid glob brace expression"): + expand_braces(pattern) + class TestMultiFileContentReplacer: FILES = [