diff --git a/.github/workflows/fuzz.yml b/.github/workflows/fuzz.yml new file mode 100644 index 0000000..05a2bfe --- /dev/null +++ b/.github/workflows/fuzz.yml @@ -0,0 +1,28 @@ +name: "Fuzz" + +on: + pull_request: + branches: [main] + +jobs: + fuzz: + name: Fuzz smoke test (10s/target) + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - name: Install Nix + uses: DeterminateSystems/nix-installer-action@v16 + - name: Run the Magic Nix Cache + uses: DeterminateSystems/magic-nix-cache-action@v8 + - uses: actions/checkout@v4 + - name: Cache fuzz build artifacts + uses: actions/cache@v4 + with: + path: fuzz/target + key: fuzz-${{ runner.os }}-${{ hashFiles('fuzz/Cargo.lock', 'rust-toolchain.toml') }} + restore-keys: | + fuzz-${{ runner.os }}- + - name: Run fuzz targets + env: + FUZZ_SECONDS: 10 + run: nix run .#fuzz diff --git a/Makefile b/Makefile index bb02ec2..2d24556 100644 --- a/Makefile +++ b/Makefile @@ -42,4 +42,4 @@ sqlx-prepare: # `nix run .#fuzz` and the Concourse `fuzz` job. Auto-discovers targets via # `cargo fuzz list`; runs them for $(FUZZ_TIME)s. Corpus in fuzz/corpus/ (gitignored). fuzz: - FUZZ_SECONDS=$(FUZZ_TIME) bash ci/vendor/tasks/fuzz.sh + SQLX_OFFLINE=true FUZZ_SECONDS=$(FUZZ_TIME) bash ci/vendor/tasks/fuzz.sh diff --git a/flake.nix b/flake.nix index b5b11b4..a60a24d 100644 --- a/flake.nix +++ b/flake.nix @@ -375,6 +375,7 @@ # — no Postgres. FUZZ_SECONDS etc. are passed through the environment. fuzz-runner = pkgs.writeShellScriptBin "fuzz" '' set -e + export SQLX_OFFLINE=true export PATH="${pkgs.lib.makeBinPath [ rustToolchain pkgs.cargo-fuzz diff --git a/fuzz/Cargo.lock b/fuzz/Cargo.lock index 036be0e..e06b289 100644 --- a/fuzz/Cargo.lock +++ b/fuzz/Cargo.lock @@ -195,9 +195,9 @@ checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "convert_case" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "affbf0190ed2caf063e3def54ff444b449371d55c58e513a95ab98eca50adb49" +checksum = "1af709f1f33454bf52eadfc8c78b3b9ef9cb26fb54d16dc9cd9a7299f899fd1b" dependencies = [ "unicode-segmentation", ] @@ -472,9 +472,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "es-entity" -version = "0.12.3" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c87798b941975265c631a0c4eb350bedad86ac4620012d82e21bc67c5dc44d0" +checksum = "19321291ff5d9ce21ccb1c9d2023fe0b6fca71dd28467fff50776d18e8fb9e2e" dependencies = [ "async-stream", "chrono", @@ -499,9 +499,9 @@ dependencies = [ [[package]] name = "es-entity-macros" -version = "0.12.3" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3af0555969e3acd0f146741b43831761b32d72339e29944eefc581d4e0db3672" +checksum = "c51299af4c4e660282802aa91235f673d6ed79f5032d65c6786cb53aff738748" dependencies = [ "convert_case", "darling 0.24.0", @@ -966,9 +966,9 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "job" -version = "0.7.1" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68bf46438d68f1d1497132533e03c69adc87a141c0b9effdcab4f27ba7b8908f" +checksum = "165584b25b7bb6fb21467498b8332812bc41185f29c377bbdc884d7bb9c162b2" dependencies = [ "async-trait", "chrono", @@ -1161,7 +1161,7 @@ dependencies = [ [[package]] name = "obix" -version = "0.7.2-dev" +version = "0.12.4-dev" dependencies = [ "async-trait", "chrono", @@ -1182,7 +1182,7 @@ dependencies = [ [[package]] name = "obix-fuzz" -version = "0.0.0" +version = "0.12.4-dev" dependencies = [ "chrono", "libfuzzer-sys", @@ -1194,7 +1194,7 @@ dependencies = [ [[package]] name = "obix-macros" -version = "0.7.2-dev" +version = "0.12.4-dev" dependencies = [ "darling 0.24.0", "proc-macro2", diff --git a/fuzz/fuzz_targets/fuzz_decode_persistent_event.rs b/fuzz/fuzz_targets/fuzz_decode_persistent_event.rs index 68c5be2..afd9b1d 100644 --- a/fuzz/fuzz_targets/fuzz_decode_persistent_event.rs +++ b/fuzz/fuzz_targets/fuzz_decode_persistent_event.rs @@ -28,7 +28,7 @@ use libfuzzer_sys::fuzz_target; use chrono::Utc; use obix::out::OutboxEventId; -use obix::{EventSequence, UndecodableEventError, decode_persistent_event}; +use obix::{CommitGroupId, EventSequence, UndecodableEventError, decode_persistent_event}; use serde::{Deserialize, Serialize}; use uuid::Uuid; @@ -58,6 +58,7 @@ fuzz_target!(|data: &[u8]| { let id = OutboxEventId::from(Uuid::nil()); let sequence = 0u64; let recorded_at = Utc::now(); + let commit_group = CommitGroupId::from(0i64); match decode_persistent_event::( id, @@ -65,6 +66,7 @@ fuzz_target!(|data: &[u8]| { recorded_at, None, payload.clone(), + commit_group, ) { Ok(event) => { if must_be_ok_with_none { @@ -86,6 +88,7 @@ fuzz_target!(|data: &[u8]| { assert_eq!(event.id, id); assert_eq!(u64::from(event.sequence), sequence); assert_eq!(event.recorded_at, recorded_at); + assert_eq!(event.commit_group, commit_group); assert!(event.tracing_context.is_none()); } Err(UndecodableEventError { @@ -93,6 +96,7 @@ fuzz_target!(|data: &[u8]| { sequence: err_seq, recorded_at: err_ts, failure, + commit_group: err_cg, }) => { // `None` can never be undecodable — that's the placeholder path. let raw = payload @@ -107,6 +111,7 @@ fuzz_target!(|data: &[u8]| { assert_eq!(err_id, id); assert_eq!(err_seq, EventSequence::from(sequence)); assert_eq!(err_ts, recorded_at); + assert_eq!(err_cg, commit_group); } } });