fix: harden verifier and CLI against malformed-input edge cases#8
Merged
Conversation
A full-program test pass surfaced four reachable edge cases. None of them change the canonical output for any currently-valid input (the demo WAL chain root is unchanged), so existing signatures and cross-language vectors still verify; the changes only refuse or neutralize bad input. 1. canonical JSON: refuse integers whose magnitude exceeds 2^53-1 (Number.MAX_SAFE_INTEGER). Such an integer is exact in Rust but a JS verifier that parsed the WAL with JSON.parse already rounded it, so the two canonical forms (and payload hashes) would silently diverge. The former i64 bound is now the JS-safe bound the docs already assumed. 2. canonical JSON: reject two object keys that collapse to the same key after NFC normalization instead of emitting duplicate, non-injective JSON that no JS reimplementation reproduces. 3. lenient verifier and inspect --stats: a record carrying sequence = u64::MAX overflowed prev_seq + 1 (panic in debug, silent wrap in release), violating spine-core's no-panic guarantee. Use saturating_add. The strict verifier was never affected because its genesis must carry sequence 1. 4. syslog export: escape CR/LF and other C0 control characters in the MSG field. A newline in a producer-controlled field (event_type) could otherwise split the line and forge an extra syslog record. Adds a regression test for each.
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.
Summary
A full-program test pass surfaced four reachable edge cases. None of them change the canonical output for any currently-valid input (the demo WAL chain root is unchanged), so existing signatures and cross-language vectors still verify. The changes only refuse or neutralize malformed input.
Fixes
2^53-1(Number.MAX_SAFE_INTEGER) are now refused. They are exact in Rust, but a JS verifier that parsed the WAL withJSON.parsealready rounded them, so the two canonical forms (and payload hashes) would silently diverge. The former i64 bound is now the JS-safe bound the module docs already assumed.DuplicateKeyAfterNfc) instead of emitting duplicate, non-injective JSON that no JS reimplementation reproduces.inspect --stats. A record carryingsequence = u64::MAXoverflowedprev_seq + 1(panic in debug, silent wrap in release), violating spine-core's no-panic guarantee. Now usessaturating_add. The strict verifier was never affected because its genesis must carry sequence 1.syslog_escapenow escapes CR/LF and other C0 control characters in the MSG field. A newline in a producer-controlled field (event_type) could otherwise split the line and forge an extra syslog record.Tests
Adds a regression test for each fix (+3 in spine-core, +2 in the CLI smoke suite).
Verification
cargo fmt --all --checkclean;cargo clippy --workspace --all-targets -- -D warningsclean.cargo test --workspace --all-features: all pass (92 core, 21 CLI smoke, 7 cross-language vectors, 4 parity, 3 wasm).