Run the same checks as CI before opening a pull request:
cargo fmt --all -- --check
cargo clippy --all-targets --all-features -- -D warnings
cargo test --allUnit and integration tests live next to the code (#[cfg(test)] modules) and in
tests/. Decoding changes must include malformed-input tests. The shared fixtures/malformed/ corpus contains small, named samples for truncated XDR, invalid discriminants, empty input, and an overlong length prefix. crates/devkit-xdr/tests/malformed_corpus.rs runs each fixture through its intended decoder and requires a structured DevkitError::Decode; an unexpected successful decode or panic fails the test.
CI runs the suite on Linux, macOS, and Windows. The following tests pin behavior that otherwise differs between hosts:
crates/devkit-xdr/tests/endianness.rsasserts XDR's big-endian wire format with explicit byte sequences (ScVal::U32,ScVal::I32, andScVal::I64), round-trips them, and checks that base64/JSON output is host-independent.crates/devkit-core/tests/cross_platform.rsasserts that native and forward-slash paths produce the same components, that.components are removed, and that parsers accept CRLF-terminated input.crates/devkit-cli/tests/path_normalization.rsrunsinspect-wasmwith a native path, a forward-slash path, and a path containing.., and requires byte-identical JSON output.
Use explicit byte arrays rather than values derived from the host when testing encodings, and compare path components rather than rendered separator strings.
Fuzz targets live in the standalone fuzz/ crate (it is not part of the main
workspace). Targets exercise the untrusted-input decoders:
| Target | Entry point |
|---|---|
decode_scval |
devkit_xdr::inspect_scval_base64 |
decode_envelope |
devkit_xdr::inspect_envelope_base64 |
decode_event |
devkit_xdr::inspect_event_base64 |
Fuzzing requires a nightly toolchain and cargo-fuzz:
cargo install cargo-fuzz
cd fuzz
cargo +nightly fuzz run decode_scval -- -max_total_time=60Targets must not touch the filesystem and must not panic on arbitrary input:
every failure should be a structured DevkitError.
- Add
fuzz/fuzz_targets/<name>.rsusing thelibfuzzer_sys::fuzz_target!macro. - Register a
[[bin]]entry for it infuzz/Cargo.toml. - The scheduled job discovers targets automatically; no workflow change needed.
.github/workflows/fuzz.yml runs weekly (Mondays at 03:00 UTC) and on demand via
workflow_dispatch. It:
- Discovers every target under
fuzz/fuzz_targets/. - Runs each target for a bounded time (
60seconds by default, overridable from the dispatch input). - Fails if any target crashes or leaves a crash artifact in
fuzz/artifacts. - Uploads
fuzz/artifactsas thefuzz-crashesartifact when a run fails.
Runs are intentionally short so they never slow normal pull-request CI.
The workflow uses dtolnay/rust-toolchain@nightly. To pin a specific nightly,
change that reference to a dated toolchain, for example:
- uses: dtolnay/rust-toolchain@master
with:
toolchain: nightly-2026-01-01Download the fuzz-crashes artifact, then re-run the offending input:
cd fuzz
cargo +nightly fuzz run decode_scval artifacts/decode_scval/<crash-file>