Skip to content

fix(rust): add XML round-trip fuzz harness, bump config-disassembler to 0.10.8 - #82

Merged
mcarvin8 merged 2 commits into
mainfrom
test/xml-roundtrip-fuzz
Sep 9, 2026
Merged

mcarvin8 merged 2 commits into
mainfrom
test/xml-roundtrip-fuzz

Conversation

@mcarvin8

@mcarvin8 mcarvin8 commented Sep 9, 2026

Copy link
Copy Markdown
Owner

Summary

  • Adds a permanent property-based fuzz test (test/xml-roundtrip-fuzz.spec.ts, fast-check devDependency) for the decompose/recompose round trip, ported from the downstream consumer (mcarvin8/sf-decomposer) that first found #127/#128/#130/#132 this way. Checks two properties matching this project's own byte-retention/idempotence conventions: no content loss after one round trip, and byte-identical output on a second round trip.
  • Bumps config-disassembler 0.10.7 -> 0.10.8, pulling in mcarvin8/config-disassembler#134: four related bugs in flush_text_buffer that lost or duplicated text mixed with child elements and CDATA. This is the fourth and final fix from this fuzzing effort, following #127/#128/#130.
  • These two changes are bundled in one PR/commit-pair because the fuzz test was correctly red against the previously-pinned 0.10.7 (it's what found the #134 bugs) — bumping the dependency is what makes it green, per this repo's existing "hold until upstream lands" pattern.
  • No API changes on the Node side.

Test plan

  • cargo build / cargo test against 0.10.8 — clean
  • npm run build -- --target aarch64-pc-windows-msvc (this machine's real host arch) then npm test — 13/13 files, 95/95 tests passing, including the new fuzz test
  • Fuzz test run independently 3+ times with fresh random seeds — all green
  • During development this was validated with 1000+ generated cases via a local [patch.crates-io] path override (see file header comment) before the fix was even released
  • Pre-push hook (release build + full test suite) passing

🤖 Generated with Claude Code

https://claude.ai/code/session_011ADqqfdwfnhTPJQp17sH3C

mcarvin8 and others added 2 commits September 9, 2026 15:02
Adds fast-check as a devDependency and a generator that produces
arbitrary nested XML shapes (mixed element/text/CDATA/comment content,
unicode, whitespace-only nodes) instead of relying only on curated
fixtures, ported from the downstream consumer (mcarvin8/sf-decomposer)
that first found #127/#128/#130/#132 this way.

Checks the same tolerance model as this project's byte-retention +
idempotence conventions: every non-whitespace leaf value must survive
one round trip, and a second round trip must be byte-identical to the
first. numRuns kept modest (100) for regular CI; bump locally for a
deeper sweep when iterating on a fix (see file header for the
[patch.crates-io] local-iteration workflow this was developed against).

NOT green yet against the currently pinned config-disassembler 0.10.7:
it correctly fails on a fourth family of bugs (mcarvin8/config-disassembler#134,
not yet released) found via this same harness. Will go green once that
lands and this repo's dependency is bumped in the same commit/PR as this
one, matching the existing "hold until upstream lands" pattern already
used for #127/#128/#130/#132.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_011ADqqfdwfnhTPJQp17sH3C
Bumps the underlying config-disassembler Rust crate 0.10.7 -> 0.10.8,
pulling in mcarvin8/config-disassembler#134: four related bugs in
flush_text_buffer that lost or duplicated text mixed with child elements
and CDATA (whitespace trimmed off real content on concatenation,
whitespace-only prior runs permanently baked into merged values causing
unbounded growth on repeated round trips, and real text silently dropped
once CDATA was present on the same element).

This is the fourth and final fix from the property-based fuzzing effort
downstream in mcarvin8/sf-decomposer, following #127 (0.10.4), #128
(0.10.5), and #130 (0.10.6). The fuzz harness added to this repo in the
prior commit (test/xml-roundtrip-fuzz.spec.ts) is now green against this
version - 13/13 test files, 95/95 tests passing, confirmed stable across
multiple independently-seeded runs.

No API changes on the Node side -- pure dependency bump. Verified with
`cargo build`/`cargo test` against 0.10.8, plus a full native-binding
`npm test` run built for this machine's actual host arch
(aarch64-pc-windows-msvc).

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_011ADqqfdwfnhTPJQp17sH3C
@mcarvin8 mcarvin8 changed the title test: add XML round-trip fuzz harness, bump config-disassembler to 0.10.8 fix: add XML round-trip fuzz harness, bump config-disassembler to 0.10.8 Sep 9, 2026
@mcarvin8 mcarvin8 changed the title fix: add XML round-trip fuzz harness, bump config-disassembler to 0.10.8 fix(rust): add XML round-trip fuzz harness, bump config-disassembler to 0.10.8 Sep 9, 2026
@mcarvin8
mcarvin8 merged commit 2850d3f into main Sep 9, 2026
3 checks passed
@mcarvin8
mcarvin8 deleted the test/xml-roundtrip-fuzz branch September 9, 2026 19:10
mcarvin8 added a commit to mcarvin8/sf-decomposer that referenced this pull request Sep 9, 2026
…to 3.4.7 (#602)

* test: add property-based fuzz test for XML decompose/recompose round trip

Adds fast-check as a devDependency and a generator that produces arbitrary
nested XML shapes (mixed element/text/CDATA/comment content, unicode,
whitespace-only nodes) instead of relying only on curated fixtures.

Checks the same tolerance model as the perf suite's byte-retention +
idempotence guards: every non-whitespace leaf value must survive one round
trip, and a second round trip must be byte-identical to the first.

This already found a real bug in config-disassembler (an element with both
a real child and direct mixed content, e.g. <item><fullName>X</fullName>
<![CDATA[..]]></item>, silently drops the CDATA/comment on disassembly --
see mcarvin8/config-disassembler#127). NOT wiring this into `npm test`
yet: it currently fails against the published [email protected]
until that fix lands and this repo's dependency is bumped.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_011ADqqfdwfnhTPJQp17sH3C

* fix(deps): bump config-disassembler to 3.4.3

Pulls in mcarvin8/config-disassembler-node#72 / mcarvin8/config-disassembler#127:
an XML element with both a real child element and its own direct mixed
content (e.g. <item><fullName>X</fullName><![CDATA[..]]></item>) no longer
silently drops the CDATA/comment/text on disassembly.

Verified: [email protected] and all 9 platform binaries
confirmed published on npm (tarballs inspected directly, not just version
metadata). Full sf-decomposer suite re-run against the bump: 618/619
passing - the one failure is the still-open comment-double-escape bug
(config-disassembler#128), unrelated to this fix and tracked separately
in test/units/xmlRoundtripFuzz.test.ts, which stays out of `npm test`
until that lands too.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_011ADqqfdwfnhTPJQp17sH3C

* test: fix fuzz test false positive on quoted text leaves

sanitizeText stripped <, &, > but not quote characters. A literal " or '
in plain text content is legal XML but gets entity-encoded (&quot;/&apos;)
by the writer on output - the same as <, &, >. The leaf-value substring
check was comparing against the raw (unescaped) form, so any generated
text leaf containing a quote produced a false "content missing" failure
even though the data was fully preserved, just re-encoded.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_011ADqqfdwfnhTPJQp17sH3C

* fix(deps): bump config-disassembler to 3.4.4

Pulls in mcarvin8/config-disassembler-node#74 / mcarvin8/config-disassembler#128:
comment content containing a literal & no longer gains an extra &amp;
layer of escaping on every successive disassemble/reassemble cycle.

Verified: [email protected] and all 9 platform binaries
confirmed published on npm (tarballs inspected directly for win32-x64 and
win32-arm64). Full sf-decomposer suite re-run against the bump: 618/619
passing - the one failure is a newly-found, distinct bug (multiple sibling
XML comments under the same element: only the last one survives, since
the intermediate parse representation stores #comment as a single string
key rather than an array), unrelated to either fix already released and
not yet reported upstream.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_011ADqqfdwfnhTPJQp17sH3C

* fix(deps): bump config-disassembler to 3.4.5

Pulls in mcarvin8/config-disassembler-node#78 / mcarvin8/config-disassembler#130:
multiple sibling XML comments under the same element are now all preserved
instead of the second silently overwriting the first.

Verified: [email protected] and all 9 platform binaries
confirmed published on npm. Full sf-decomposer suite re-run against the
bump: 618/619 passing - the one failure is a newly-found, distinct and
unbounded idempotence bug (an element with both a comment and CDATA as
direct mixed content grows two extra blank lines between them on every
successive disassemble/reassemble cycle, forever), unrelated to the three
fixes already released and not yet reported upstream.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_011ADqqfdwfnhTPJQp17sH3C

* fix(deps): bump config-disassembler to 3.4.6

Pulls in mcarvin8/config-disassembler-node#80 / mcarvin8/config-disassembler#132:
a comment immediately followed by CDATA no longer grows extra blank lines
between them on every successive disassemble/reassemble cycle.

Verified: [email protected] and all 9 platform binaries
confirmed published on npm. Full sf-decomposer suite re-run against the
bump: 618/619 passing - the one failure is a fifth, distinct bug (trailing
non-whitespace text after a child element loses its own leading/trailing
whitespace when concatenated onto an earlier whitespace-only text run on
the same element, e.g. "( " becomes "(" - flush_text_buffer's "append"
branch uses parse_text_value's trimmed output where the "first text run"
branch uses the untrimmed raw value), unrelated to the four fixes already
released and not yet reported upstream.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_011ADqqfdwfnhTPJQp17sH3C

* fix(deps): bump config-disassembler to 3.4.7

Pulls in mcarvin8/config-disassembler-node#82 / mcarvin8/config-disassembler#134:
four related bugs in flush_text_buffer that lost or duplicated text mixed
with child elements and CDATA (whitespace trimmed off real content on
concatenation, whitespace-only prior runs permanently baked into merged
values causing unbounded growth on repeated round trips, and real text
silently dropped once CDATA was present on the same element).

This is the fourth and final fix from the property-based fuzzing effort
that started with #127 (3.4.3), #128 (3.4.4), and #130 (3.4.5). The fuzz
test (test/units/xmlRoundtripFuzz.test.ts) is finally green: full suite
re-run, 34/34 files, 619/619 tests passing. Confirmed stable across 4
independently-seeded runs of the fuzz test alone before running the full
suite.

Verified: [email protected] and all 9 platform binaries
confirmed published on npm.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_011ADqqfdwfnhTPJQp17sH3C

---------

Co-authored-by: Claude Sonnet 5 <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant