Repository navigation
fix(testing): render the diagnostic slot in the fuzz echo gate - #2797
Conversation
Nightly fuzz run 295 went red on `arithmetic_fuzz` with the 6-byte input
`wZTok:`. Arithmetic diagnostics render `{diag_echo(expr.trim())}: {msg}`,
so the expression's trailing colon lands next to the message separator's:
bash: line 1: wZTok:: syntax error in expression (error token is ":")
That spells the banned parser-token shape `Tok::` across the join while the
script carries only `Tok:`. The tokenizer's `Tok` enum is never formatted and
`Tok::` appears nowhere in the script, so this is bashkit echoing the
expression back the way real bash does -- a false positive, not a TM-INF-022
leak.
`input_echo_would_trip` matched the raw input, which cannot see a shape the
template's own punctuation completes. It now renders the slot with the
punctuation a diagnostic places around it (`DIAGNOSTIC_ECHO_PAD`) before
matching, and matches the trimmed text because the slot holds `expr.trim()`.
The same join completes the space-prefixed ` { code:` shape from the
`bash: line N: ` prefix.
Kept in the gate rather than widening `strip_real_shell_error_lines` to the
arithmetic template on purpose: that template's `{msg}` half is bashkit's own
text, the one slot where a genuine Debug leak would appear, so stripping the
line would blind the detector exactly where it has to look. A skipped input
hides nothing, because the skip condition is that the shape is attributable
to the input.
The crash input reproduces the CI panic byte-for-byte before the fix (same
`testing.rs:155`, same raw stderr) and is gated after it. The pre-existing
run 270/271/272 regressions and the negative tests that prove the gate did
not become blanket all still pass.
Claude-Session: https://claude.ai/code/session_01Wy7MBv7EWLPKBj4GqJeH5s
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
bashkit | 668a400 | Commit Preview URL Branch Preview URL |
Oct 30 2026, 09:28 AM |
|
The failure
Why it is not this PR's
Fix None in this PR, deliberately. Closing the residual pre-3.13 window is a change to the teardown protocol in Generated by Claude Code |
What changed
bashkit::testing::input_echo_would_trip— the pre-filter fuzz targets use toskip inputs the shell will echo back into a diagnostic — now renders the echo
slot with the punctuation a diagnostic places around it before matching, and
matches the trimmed text because the slot holds
expr.trim().Test-harness only. No runtime behavior changes: no builtin, interpreter or
diagnostic text is touched, and the leak detector itself stays exactly as
strict for every input that does run.
Why
Nightly
Fuzz Testingrun 295 went red onarithmetic_fuzzwith the 6-byteinput
wZTok:, and stayed red on main. Arithmetic diagnostics render{diag_echo(expr.trim())}: {msg}, so the expression's trailing colon landsnext to the message separator's:
That spells the banned parser-token shape
Tok::across the join while thescript carries only
Tok:. The tokenizer'sTokenum is never formatted andTok::appears nowhere in the script — this is bashkit echoing the expressionback the way real bash does, so it is a false positive, not a TM-INF-022 leak.
The gate matched the raw input, which structurally cannot see a shape the
template's own punctuation completes. Runs 271 and 272 were the same
false-positive class caught inside the input; this is the first one spelled
at the boundary.
Kept in the gate rather than widening
strip_real_shell_error_linesto thearithmetic template on purpose: that template's
{msg}half is bashkit's owntext, the one slot where a genuine Debug leak would appear, so stripping the
line would blind the detector exactly where it has to look. A skipped input
hides nothing, because the skip condition is that the shape is attributable to
the input.
Before / After
The crash input is the exact one CI reported — the file's SHA1 reproduces the
artifact name
crash-8d7001253cb8a09eb51d50e3be6b6267565237b5:Before — the fuzz target's own path panics, byte-for-byte as in run 295
(same
testing.rs:155, same raw stderr):After — the gate recognizes the echo and the target skips the input; the
diagnostic itself is unchanged and still a faithful, bounded echo.
The gate stays narrow rather than becoming blanket.
wZTo:— one charactershort of the shape — is still admitted and still runs under the strict
detector, and the pre-existing run 270/271/272 regressions plus
same_shape_without_the_banned_text_is_still_checkedall still pass.Risk
arithmetic_fuzz,glob_fuzzandcpython_fuzzlose a sliver of coverage: only inputs whose own text spellsa banned shape against the template's punctuation, which is exactly the set
that can only produce false positives.
that the shape is attributable to the input. Every input that does run is
checked by the unchanged detector.
Checklist
gate (
input_echo_would_trip_sees_the_diagnostic_separator, covering thetrimmed and space-prefixed
{ code:joins and two negative cases) andan end-to-end scaffold regression (
run_295_banned_shape_straddles_the_separator,near_miss_at_the_separator_is_still_checked). Both confirmed failingbefore the fix and passing after.
#[doc(hidden)]test helper,no caller outside the fuzz targets and scaffold tests.
knowledge/security/threat-model.mdrecords run 295and why the fix belongs in the gate rather than the strip layer.
https://claude.ai/code/session_01Wy7MBv7EWLPKBj4GqJeH5s
Generated by Claude Code