fix(testing): match shell echoes the shell actually produces - #2320
Merged
Merged
Conversation
`glob_fuzz` run 219 went red on `\n \0{ code:<(])\n`, the second failure
of this class in two days. Run 218's fix corrected one diagnostic's
wording; this corrects the two harness gaps underneath both.
The pre-filter checked the raw input bytes, but the shell transforms them
before echoing: NUL is dropped during word expansion, so `\0{ code:` and
`</r\0ustc/` slip past a literal `contains` and reappear in stderr as
` { code:` and `/rustc/`. Targets now call `input_echo_would_trip`, which
checks the input as the shell will render it back.
The echo filter was line-based, but the user-input slot can contain
newlines: a command name ending in `\n` renders bash's one-line
`command not found` template across two lines, and neither half matched.
Matching is now span-based — an unclosed `bash: `/`ls: cannot access `
line extends to the first later line ending in a template suffix.
Closing on the earliest candidate keeps the span minimal, so a leak
printed after a complete diagnostic still survives; and a leak cannot be
swallowed inside a span, because each shell diagnostic is formatted and
written as one string with nothing interleaved. The pre-existing
`strip_keeps_*` tests pin that direction and still pass.
Quote and backslash removal can synthesize banned shapes the same way
NUL stripping does, which is why the detector no longer depends on the
pre-filter alone — the two are independent defenses.
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
bashkit | 39400b5 | Commit Preview URL Branch Preview URL |
Aug 21 2026, 10:53 AM |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed
The fuzz leak detector now recognizes a shell echo of user input regardless of how the shell transformed that input, and regardless of whether the diagnostic fits on one line. Test-harness and fuzz-target only — no shell behavior changes.
Why
glob_fuzzwent red again onmain(run 219, input\n \0{ code:<(])\n) — the second failure of this class in two days:#2319 fixed one diagnostic's wording. That was necessary but treated a symptom. Run 219 exposed the two harness gaps underneath both failures:
1. The pre-filter checked raw bytes; the shell transforms them.
glob_fuzzskips inputs containing aUNIVERSAL_BANNEDshape, but NUL is dropped during word expansion — so\0{ code:and</r\0ustc/slip past a literalcontainsand reappear in stderr as{ code:and/rustc/. Both crashes hinge on exactly this. Targets now callinput_echo_would_trip, which checks the input as the shell will render it back.2. The echo filter was line-based; the input slot can contain newlines. The command name here ends in
\n, so bash's one-linebash: %s: command not foundtemplate renders across two lines and neither half matched. Matching is now span-based: an unclosedbash:/ls: cannot accessline extends to the first later line ending in a template suffix.Quote and backslash removal can synthesize banned shapes the same way NUL stripping does. That's why the detector no longer leans on the pre-filter alone — the two are independent defenses, and fixing only the pre-filter would leave the same class open.
Before / After
Both crash inputs replayed through the real fuzz target, rebuilt on this branch:
On
main, the first of those aborts withlibFuzzer: deadly signal.Risk
src/testing.rsis#[doc(hidden)]test-only.Span matching widens what gets stripped, so the guard is that it strips as little as possible: the span closes on the earliest candidate line, so a leak printed after a complete diagnostic survives (
strip_span_stops_at_the_first_closing_line), and an unclosedbash:line swallows nothing (strip_keeps_unclosed_bash_prefix_span). A leak cannot be swallowed inside a span, because each shell diagnostic is formatted and written as one string with nothing interleaved.The pre-existing
strip_keeps_*tests — which exist precisely to catch over-stripping — all still pass unmodified.Verified: 16/16
testing::unit tests, 6/6glob_fuzzscaffold tests, workspace lib/bins/tests, doc tests,realfs,failpoints,proptest_security, clippy-D warnings,cargo fmt,check_okf.py,check_doc_links.py, plus a longglob_fuzzsession against the rebuilt target (CI reached its failure at ~121k executions).ssh_supabase_connectsfails locally (sandbox blocks outbound port 22) — environmental, green onmainin CI.Checklist
Generated by Claude Code