Skip to content

feat: feature-gated Arbitrary derives + structure-aware fuzz harness (#44) - #46

Merged
stormer78 merged 1 commit into
mainfrom
feat/arbitrary-fuzzing-44
Jun 14, 2026
Merged

feat: feature-gated Arbitrary derives + structure-aware fuzz harness (#44)#46
stormer78 merged 1 commit into
mainfrom
feat/arbitrary-fuzzing-44

Conversation

@stormer78

Copy link
Copy Markdown
Collaborator

Closes #44.

Adds an off-by-default arbitrary feature so downstream consumers can do structure-aware, coverage-guided fuzzing of the chain verifier, plus a workspace-detached fuzz/ crate with cargo-fuzz targets. Everything new is additive or behind the feature flag — no public-API breakage.

Arbitrary surface (feature = "arbitrary")

  • Derive on the local leaf types: Version, Multibase, Witness, Witnesses, Parameters (the computed #[serde(skip)] fields are #[arbitrary(default)]), Parameters1_0, Parameters1_0Pre.
  • Hand-written impls for the LogEntry types in src/arbitrary_impls.rs — their chrono::DateTime / serde_json::Value / DataIntegrityProof fields are foreign types the orphan rule won't let us derive through. state is a bounded arbitrary JSON value; proofs are built from arbitrary parts via the public DataIntegrityProof::new, so the structural proof path (shape enforcement, did:key resolution, cryptosuite gating) is reachable without valid signatures.

Note on the "wrinkles" from the issue: Arc<T> is not a blocker (arbitrary 1.x covers it); the real foreign-field blocker was serde_json::Value on state, handled by the bounded generator.

Verifier assembly

  • DIDWebVHState::from_log_entries(Vec<LogEntry>) — the documented, filesystem-free way to drive validate() from an in-memory chain (useful beyond fuzzing). version_number is best-effort so deliberately broken chains still reach the verifier.

Fuzzing (fuzz/)

  • Targets: parameters_validate, logentry_deserialize, chain_validate, proof_verify (the proof-verification path).
  • fuzz/ has its own empty [workspace] table → normal cargo build/test/clippy never compile it; nightly + libfuzzer stay out of default CI.
  • New Fuzz workflow runs only on workflow_dispatch + weekly cron.
  • Smoke-run locally: ~6M total executions across all four targets, no crashes.

Dependency refresh (required to compile cleanly)

  • cargo update; affinidi-data-integrity 0.7.1 → 0.7.6 made DataIntegrityProof #[non_exhaustive], so the existing test/test-utils struct literals are converted to DataIntegrityProof::new().

Housekeeping

  • Version bumped 0.5.4 → 0.5.5; CHANGELOG + README updated (new Feature Flags row + "Fuzzing" section).

Verification

  • cargo fmt -- --check
  • cargo clippy --all-features --tests --examples -- -D warnings
  • cargo test --all-features ✅ (435 + integration, 0 failed) and default cargo test

…44)

Add an off-by-default `arbitrary` feature so downstream consumers can do
structure-aware, coverage-guided fuzzing of the chain verifier, and ship a
workspace-detached `fuzz/` crate with cargo-fuzz targets.

Arbitrary surface (behind `feature = "arbitrary"`):
- Derive on the local leaf types: Version, Multibase, Witness, Witnesses,
  Parameters (computed #[serde(skip)] fields are #[arbitrary(default)]),
  Parameters1_0, Parameters1_0Pre.
- Hand-written impls for the log-entry types in src/arbitrary_impls.rs —
  their chrono::DateTime / serde_json::Value / DataIntegrityProof fields are
  foreign types the orphan rule won't let us derive through. `state` is a
  bounded arbitrary JSON value; proofs are built from arbitrary parts via the
  public DataIntegrityProof::new so the structural proof path (shape
  enforcement, did:key resolution, cryptosuite gating) is reachable without
  valid signatures.

Verifier assembly:
- Add DIDWebVHState::from_log_entries(Vec<LogEntry>) — the documented,
  filesystem-free way to drive validate() from an in-memory chain (also
  useful beyond fuzzing). version_number is best-effort so deliberately
  broken chains still reach the verifier.

Fuzzing (fuzz/, own empty [workspace] so normal CI never builds it):
- Targets: parameters_validate, logentry_deserialize, chain_validate,
  proof_verify. Smoke-run ~6M execs total, no crashes.
- New Fuzz workflow runs only on workflow_dispatch + weekly cron (nightly +
  cargo-fuzz), off the default PR/push CI path.

Dependency refresh (required for the above to compile cleanly):
- cargo update; affinidi-data-integrity 0.7.1 -> 0.7.6 made
  DataIntegrityProof #[non_exhaustive], so the existing test/test_utils
  struct literals are converted to DataIntegrityProof::new().

cargo fmt / clippy --all-features / test --all-features all clean.

Closes #44
@stormer78
stormer78 merged commit cbf35ef into main Jun 14, 2026
5 of 6 checks passed
@stormer78
stormer78 deleted the feat/arbitrary-fuzzing-44 branch June 14, 2026 08:11
stormer78 added a commit to affinidi/affinidi-webvh-service that referenced this pull request Jun 14, 2026
…esh lockfile (#46)

* chore: bump didwebvh-rs to 0.5.5 and refresh dependency lockfile

Bumps didwebvh-rs 0.5.4 -> 0.5.5, which adds the off-by-default
`arbitrary` feature for structure-aware fuzzing of the chain verifier
(decentralized-identity/didwebvh-rs#46, closing #44; see
#45).

Also refreshes the rest of the lockfile to the latest semver-compatible
versions within the existing Cargo.toml ranges (affinidi-* crates, aws-sdk-*,
openssl, time, wasm-bindgen, zeroize, etc.). vta-sdk is intentionally left
at 0.11.x (0.12.0 is held by the lockstep pin with vti-common).

Lockfile-only; no Cargo.toml manifest changes. Workspace builds clean and
the full test suite passes.

* chore: bump vta-sdk to 0.13 / vti-common to 0.10.3 (lockstep)

vta-sdk 0.13.1 and vti-common 0.10.3 are the aligned pair on crates.io
(vti-common 0.10.3 re-pins onto vta-sdk ^0.13). Bumps the workspace
vta-sdk pin 0.11 -> 0.13, the four vti-common member pins 0.10 -> 0.10.3,
and updates the lockstep comment.

A second vta-sdk 0.11.3 copy remains in the lock, pulled only by the
affinidi-messaging-test-mediator dev-dependency (mediator 0.16.1 still
pins vta-sdk ^0.11). It is confined to that test-harness subtree, does
not touch our auth wire types, and the workspace builds + tests cleanly
(no E0308) — our vta-sdk/vti-common pair is matched at 0.13.1.

Workspace builds with --tests; full suite passes (753 tests, 0 failed).
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.

Feature-gated Arbitrary derives on LogEntry/Parameters for structure-aware fuzzing

1 participant