Fix: Enforce scope on exclude patterns and improve UX - #12
Conversation
Security fix: - Add scope enforcement to prevent excluding files outside the selected directory/zip. Previously, the Browse picker allowed selecting arbitrary filesystem paths which would be silently converted to overly-broad globs. - Compute operation scope from selected directories only (files and zips contribute nothing since you can only exclude what's being glued). - Validate manual patterns to reject absolute paths, traversals, and out-of-scope references. - Disable Browse button for zip-only selections (contents unknown to GUI). - Point file picker initial folder at scope root, not zip's parent dir. - Show rejection summary when user picks out-of-scope files. UX improvement: - Hide exclude section entirely when only files are selected (no dirs/zips), since excludes only apply during directory recursion. Testing: - Add comprehensive tests for scope computation, pattern validation, and the prefix-separator trap in is_path_in_scope. - Tests use real filesystem paths via tmp_path fixture. Fixes: exclude-outside-selection sandbox escape
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughThis PR adds scope enforcement for GUI exclude handling and file picking. It computes allowed scope roots from selected inputs, validates exclude patterns and picked paths against those roots, updates picker defaults and rejection reporting, and adds tests for the new scope rules. ChangesScope-aware exclude and browse feature
Estimated code review effort: 4 (Complex) | ~60 minutes Possibly related PRs
Suggested labels: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (2)
tests/test_codegluer_gui.py (1)
335-356: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winConsider adding a test for
~home-path rejection.
validate_exclude_patternexplicitly rejects~-prefixed patterns (rule 4 in the docstring), but no test covers this branch. The absolute-path rejection is tested, but the home-path rejection is a separate code path that could regress unnoticed.✨ Suggested additional test
def test_validate_rejects_absolute_and_traversal(tmp_path): scope = [str(tmp_path)] ok, _, err = cg.validate_exclude_pattern("/etc/passwd", scope) assert not ok and "Absolute" in err ok, _, err = cg.validate_exclude_pattern("../outside.txt", scope) assert not ok and "outside" in err + ok, _, err = cg.validate_exclude_pattern("~/secret.txt", scope) + assert not ok and "Absolute" in err🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/test_codegluer_gui.py` around lines 335 - 356, Add a test in test_codegluer_gui for the `validate_exclude_pattern` home-path branch, since it already covers absolute and traversal rejection but not `~`-prefixed inputs. Extend the existing validation tests to call `cg.validate_exclude_pattern` with a `~` path and assert it is rejected with the expected error, using the `validate_exclude_pattern` symbol to locate the logic.codegluer_gui.py (1)
903-932: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winExtract the shared rejection-summary logic.
The rejection accumulation and truncated error-dialog block here (Lines 921-932) is duplicated almost verbatim in
_on_file_chooser_response(Lines 986-996). Consolidating into one helper (e.g._report_rejected_picks(rejected, n)) removes the copy and keeps the two picker paths in sync when the wording or truncation limit changes.♻️ Suggested helper extraction
def _report_rejected_picks(self, rejected: list[str], n: int) -> None: if not rejected: return summary = "\n".join(f"• {r}" for r in rejected[:10]) if len(rejected) > 10: summary += f"\n… and {len(rejected) - 10} more." self._show_error_dialog( f"Rejected {len(rejected)} of {n} pick(s)", "Only files inside the selected directory or zip " "can be excluded.\n\n" + summary, )Then both handlers call
self._report_rejected_picks(rejected, n).🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@codegluer_gui.py` around lines 903 - 932, The rejection-summary and error-dialog logic is duplicated between the picker handlers, so extract it into a shared helper such as _report_rejected_picks(rejected, n) and have both the current selection flow and _on_file_chooser_response call it. Move the truncated summary formatting and _show_error_dialog call into that helper so the rejection wording and 10-item limit stay consistent in one place.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@codegluer_gui.py`:
- Around line 903-932: The rejection-summary and error-dialog logic is
duplicated between the picker handlers, so extract it into a shared helper such
as _report_rejected_picks(rejected, n) and have both the current selection flow
and _on_file_chooser_response call it. Move the truncated summary formatting and
_show_error_dialog call into that helper so the rejection wording and 10-item
limit stay consistent in one place.
In `@tests/test_codegluer_gui.py`:
- Around line 335-356: Add a test in test_codegluer_gui for the
`validate_exclude_pattern` home-path branch, since it already covers absolute
and traversal rejection but not `~`-prefixed inputs. Extend the existing
validation tests to call `cg.validate_exclude_pattern` with a `~` path and
assert it is rejected with the expected error, using the
`validate_exclude_pattern` symbol to locate the logic.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: e6379ec3-5250-4b89-b5a4-51f4301e64ab
📒 Files selected for processing (2)
codegluer_gui.pytests/test_codegluer_gui.py
- Extract _report_rejected_picks() helper; both picker handlers now share the same 10-item truncation and wording. - Add test coverage for the ~-prefixed path rejection branch in validate_exclude_pattern (previously untested).
The assertions checking for output filenames in cmd were using substring membership on a list, which checks for exact element match. Since the output path is a single list element like '/tmp/.../Glued_Code.txt', checking 'Glued_Code.txt' in cmd would fail. Changed to iterate through cmd elements and check if the substring appears in any element, which correctly validates that the output filename is part of the full path argument. Affected tests: - test_build_command_plain_empty_output_defaults_to_txt - test_build_command_markdown_empty_output_defaults_to_md - test_build_command_custom_output_name_respected
The test_gitignore_respect_anchored test was failing after the OOM/freeze guard was added to collect_files(). The guard skips directories like 'build' by default (via DEFAULT_IGNORE_DIR_NAMES), which prevented the test from verifying .gitignore anchoring behavior on a directory named 'build'. Added skip_default_ignore_dirs=False to the collect_files() call in this test to isolate the gitignore anchoring logic from the default directory skip logic. This allows the test to verify that anchored gitignore rules (/build/) work correctly without interference from the OOM guard.
The previous implementation flagged any directory that CONTAINED a heavy subdirectory (e.g., .git, node_modules) as 'heavy', which was too aggressive. This prevented opening the file picker in normal project directories that happen to have a .git folder. The new logic: 1. Checks if the directory ITSELF is a heavy directory (e.g., the path is /home/user/project/node_modules) 2. Falls back to checking if the directory has an excessive number of entries (>500) This allows the file picker to open in normal project directories while still preventing the freeze bug when pointed at actual heavy directories like node_modules, .git, dist, etc. The freeze prevention still works because: - Opening the picker AT node_modules/.git/etc is blocked (step 1) - Opening the picker at a directory with 500+ entries is blocked (step 2) - Normal project directories with a .git folder are now allowed
Security fix:
UX improvement:
Testing:
Fixes: exclude-outside-selection sandbox escape
Summary by CodeRabbit
..traversal).