Repository navigation
fix(guards): fold shell continuations in the hooksPath guard via one shared helper (#15961) - #16414
Conversation
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Advanced Run ID: 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 |
|
Review of Verified: behavior-preserving extraction, not a rewrite. The #15938 guard's diff is pure deletion of its private Verified: the helper itself is well-tested, including the case that actually matters ( Verified: both directions covered for the consuming guard. Verified: the guard's own dogfooding note is accurate. Nothing else found. |
✅ SSOT Configuration Compliance: Passing🎉 No new hardcoded values of either class — Known backlog in |
…okspath-continuations # Conflicts: # tools/lint/_scan_helpers.py
…line into it (#15961) Bash ends a comment at the newline, so a backslash at the end of one is text. logical_lines folded it anyway, gluing the next line behind a '#'. The hooksPath guard skips comment lines, so an override written straight after such a comment went unreported, though the old physical-line scan caught it (#16414 review). A whole-line comment now always stands alone. Regression cases are in _scan_helpers_test.py and in the guard's own catch list.
|
Review at
The earlier "approve" comment on this PR was a bot notice against |
|
Delta
|
AutoBot Phase Validation ResultsSystem Maturity: 96.5% Phase Status:PASS Phase 1: Core Infrastructure: 100.0% Recommendations:
|
…t is no longer invisible (#17941) CodeRabbit. The check matched `line.startswith(("import ", "from "))`, which only ever sees column-zero imports -- so a function-local `import requests` passed it. THAT WAS NOT HYPOTHETICAL HERE. `_comment_syntax` has exactly one deferred import, `from tools.lint._scan_helpers import logical_lines` inside `_join_continuations` (#16414, delegating the fold rather than re-deriving it). Its root is `tools`, which is NOT in the allowlist -- so the guard I added one commit ago passed only because it could not see the import that would have failed it. A guard blind in exactly the place it is pointed. Now AST-based, and three shapes are classified rather than skipped: * a function-local import is found wherever it sits * a relative import is reported as `.` so it can never read as stdlib * `tools.lint._scan_helpers` is allowed BY NAME, not by its root -- permitting `tools` would admit anything that ever lands under it Ten contrast controls added, because the sweep over the two real files is clean and proves nothing on its own. The two that matter: the function-local case, which passed before this change, and `tools.lint.other`, which must be flagged or the dotted allowance would be a `tools` wildcard wearing a longer name. Mutation-verified, and this time I checked the mutation APPLIED before reading the result -- my previous attempt injected after a line the file does not contain, so it silently did nothing and the suite passed. With an INDENTED `import requests` in `_comment_syntax`: AssertionError: _comment_syntax reaches beyond stdlib and autobot_shared: ['requests'] Reverted, 34 pass.
Refs #15961
Single-issue rationale: this addresses one named gap in #15961, the shell-continuation escape in its static guard, by extracting the helper #16128 introduced. #15961 stays open: AC1 (runtime detection of a transient
-c core.hooksPath=override) is a separate mechanism.Thinking Path
repo_tests/hooks_path_override_15961_test.pymatched physical lines, so a shell\continuation hid the most harmful spelling, the persistent override:#16128 fixed the same defect in the sibling guard,
git_merge_rejects_pull_only_flags_15938_test.py, with a_logical_lines()helper. The plan recorded on #15961 was one helper, not a second copy: pasting the fold into this guard would give base two implementations of one rule, and they would drift.What Changed
Review fix:
logical_linesno longer folds out of a whole-line comment. Bash ends a comment at the newline, so a trailing\inside one is text. Folding it glued the next line behind a#, and_offending_linesskips comment lines, so an override written straight after such a comment went unreported. The old physical-line scan caught it. Regression cases are in_scan_helpers_test.pyand in the guard's own catch list.New
tools/lint/_scan_helpers.pylogical_lines(): folds backslash-newline continuations and reports each command's first physical line number. It has its own unit tests intools/lint/_scan_helpers_test.py, covering no continuation, two lines, three lines, a mid-line backslash that isn't folded, and the reported line number.hooks_path_override_15961_test.pyscans logical lines. New fixtures cover both directions:git config \+core.hooksPath /xis caught.-csplit fromcore.hooksPath=across lines is caught.git config \+--get core.hooksPathstays allowed.git_merge_rejects_pull_only_flags_15938_test.pyimports the shared helper in place of its private copy. The algorithm is byte-identical, so its behaviour is unchanged.repo_tests/slm_frontend_shell_publish_test.pykeeps its own_logical_lines. It has different semantics: it returns strings without line numbers, and strips each continued line before joining. Moving it onto the shared shape would change its behaviour, not just remove a duplicate. The difference is documented in its docstring.The helper's docstring and its unit tests use neutral tokens (
some-tool … --dangerous-flag). The hooksPath guard scans every tracked file, the helper's own files included, so a real offending spelling there tripped it twice at pre-push. The real spellings stay only in the guards' own fixtures.Verification
py_compileandast.parsepass on every touched file, and the full pre-commit suite passed at commit.test_a_relative_hookspath_defeats_hooks_in_a_worktree.--no-verifyrule): already on base, in CLAUDE_RULES.md and CLAUDE_GIT.md.GIT_CONFIG_PARAMETERS.Model Used
Claude Opus 5 (coordinator) with a Claude Sonnet 5 subagent for the implementation.
🤖 Generated with Claude Code