Repository navigation
fix(rewrite): split multi-line blocks on a lone CR separator - #3600
breisnerlopez wants to merge 2 commits into
Conversation
|
Reviewed this and I think the premise doesn't hold, and merging as-is would make things worse rather than better. The PR widens The problem: bash does not split on a bare does not run as two commands — Concretely, for ( The new test I'd suggest starting from the other end: confirm what bash actually does with a lone |
A bare `\r` (classic-Mac EOL, no trailing `\n`) is not a command boundary: bash runs `git status\rgit log` as a single command (the CR is an ordinary character in a word). The earlier approach split on it, so the rewriter emitted two `rtk` prefixes joined by a raw CR — a mangled single command that diverged from what the permission layer had approved. - lexer: tokenize a newline operator for `\n` and for the `\r` of a CRLF pair, but not for a lone `\r`, which falls through to whitespace. CRLF tokenization is unchanged, so rewrite_multiline_block still preserves the `\r\n` bytes. - rewrite_command dispatches on `\n` alone again; a lone-CR block is prefixed once, matching the one segment split_for_permissions now produces. - raw_breaks counts `\n` plus the `\r` of a CRLF, not a lone `\r`. Supersedes the split-on-CR approach (per review: bash doesn't split on a lone CR).
46e5de5 to
073f96b
Compare
|
You were right — bash doesn't split on a lone
Force-pushed the pivot over the previous commit. fmt / clippy |
|
Took a closer look at the fix (073f96b) — the core change is correct (lone 1.
The allow-rule ends up matching against text that was never what will actually execute — the same gate/execution divergence this PR set out to fix, just in the pattern matcher instead of the splitter. 2. Both look like they'd want the same "lone |
… tickets filed Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Address review: merge the \n and \r newline-operator arms in tokenize_inner into one, and extract the CRLF detection into a pub(crate) is_crlf_at(bytes, i) helper so the lexer and the registry multi-line parity check use a single source of truth for the rule. Behavior-preserving.
|
Both nits applied in
Behavior-preserving — the CRLF / lone- |
|
Apologies — I reviewed this PR in isolation across three rounds and never connected it to #3704, which is my own PR and covers the same ground. That's on me; the earlier feedback would have been much shorter had I spotted it. Now that I have, here's the comparison. I built one probe harness and ran it identically at
Every rewriter output is byte-identical between the two branches. #3704 already reproduces this PR's whole rewriter delta — the The one behaviour unique to this PR is dropping the lone-CR boundary in Why the gate should stay conservative: PowerShell reaches it too — So on a Windows Copilot/VS Code host, the The tests here
Given all that I think the right move is to close this in favour of #3704 rather than rescope it — there's no remaining delta to rescope around. But it's your call, and the credit for finding the lone-CR problem in the first place is yours: #3704 exists because of the |
Two follow-ups from /code-review high on this branch:
1. parse_golangci_run_parts's switch to the full shell tokenize() (Phase
3) fixed the intended quoted-value bug but introduced a real
regression: tokenize() splits unquoted shell metacharacters (*, ?,
`, (, ), {, }, !) into their own tokens even outside quotes, so an
unquoted glob value like `--config *.yml` desynced the flag-skip
loop and got the whole command misclassified as Unsupported.
split_token_spans's actual job - "was there a space here", not full
shell syntax - is genuinely different from tokenize()'s, so it
should not have been replaced by it. Restored split_token_spans as
its own function, now built on the shared advance_quote_state /
is_word_boundary_whitespace primitives instead of being quote-blind,
which is what actually fixes the original quoted-value bug without
the metacharacter regression. New regression test for the unquoted
case.
2. Extracted is_crlf_at() and used it in both tokenize_inner's
newline-operator guard and registry.rs's raw_breaks parity check -
this exact duplication (two independent "is this \r part of a CRLF
pair" checks) was flagged as a follow-up during the PR #3600 review
that prompted this whole consolidation, and had been reintroduced
here without actually being fixed.
All 2714 tests pass, clippy clean.
|
Closing in favor of #3704, which already lands this PR's rewriter delta byte-for-byte (raw_breaks parity, the mixed CR+LF single-prefix fix, |
Focused follow-up to #3274, taking @KuSh's suggested route: close the broad PR (now superseded by fc8054e) and cover just the one gap that commit left open — a lone
\rseparator (no\n) — using its safer per-line, guarded approach.The gap
fc8054erewrites each line of a multi-line Bash block, but the dispatch inrewrite_commandonly enters that path on'\n':A block whose only separator is a bare
\r(classic-Mac line ending, no trailing\n) falls through torewrite_single: thertkprefix lands on the first line and every following line runs raw and unfiltered — exactly the bugfc8054efixed for\n, still open for lone\r.The fix
The quote-aware lexer already tokenizes a lone
\ras a newline operator, so widening the gate totrimmed.contains(['\n', '\r'])routes these blocks throughrewrite_multiline_blockunchanged. All of its existing guards still apply (unsafe lines, cross-line continuations, quote-swallowed breaks), so a\rinside quotes stays one logical command.Why it's safe
It never over-splits relative to gating:
split_for_permissionsalready tokenizes lone\ras a boundary, so the permission layer was already evaluating each post-CR line independently — the rewriter was the only side lagging. Widening it only makes the two agree.Tests
test_lone_cr_separators_rewrites_each_line—git status\rgit log→ both prefixed.test_lone_cr_inside_quotes_rewrites_as_one_command— CR in quotes stays one command.test_split_perms_lone_cr/..._inside_quotes_not_split— permission layer splits a dangerous post-CR command on its own, and never splits a quoted CR.cargo fmt --check,clippy, and the full suite (2616) are green.