Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
fdf9063
Add cargo fuzz targets for visualsign-solana
shahan-khatchadourian-anchorage Mar 14, 2026
04a63e2
Add proptest and fuzz label-triggered CI jobs
shahan-khatchadourian-anchorage Mar 14, 2026
73c07ef
Post fuzz crash summary as PR comment on failure
shahan-khatchadourian-anchorage Mar 14, 2026
2352f90
Split proptest and fuzz workflows into separate files
shahan-khatchadourian-anchorage Mar 14, 2026
de7515d
Add reusable post-failure-comment action tagging @copilot
shahan-khatchadourian-anchorage Mar 14, 2026
0014722
Extract shared pipeline helpers into common module
shahan-khatchadourian-anchorage Mar 24, 2026
c48dda4
Add semantic pipeline tests for 8 embedded IDLs
shahan-khatchadourian-anchorage Mar 24, 2026
6a667ad
Allow triggering CI on any PR via 'ci' label
shahan-khatchadourian-anchorage Mar 24, 2026
7e3b9f0
Fix fuzz build and simplify CI workflows
shahan-khatchadourian-anchorage Mar 25, 2026
b19f3d9
Add failure labels to fuzz and proptest workflows
shahan-khatchadourian-anchorage Mar 25, 2026
0b545b9
Harden label steps in fuzz and proptest workflows
shahan-khatchadourian-anchorage Mar 25, 2026
3938dbf
docs: add cargo fuzz, semantic tests, and CI labels to testing guide
shahan-khatchadourian-anchorage Mar 25, 2026
bfde987
Address Copilot review: pin nightly, lock cargo-fuzz, fix cache key
shahan-khatchadourian-anchorage Mar 25, 2026
2a84706
Address code review: Default::default(), env var for PR number
shahan-khatchadourian-anchorage Mar 25, 2026
febf931
Fix panics on malformed transaction data in legacy instruction decodi…
shahan-khatchadourian-anchorage Mar 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions .github/workflows/fuzz.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
name: Fuzz Testing

on:
pull_request:
types: [opened, synchronize, reopened, labeled]

jobs:
fuzz:
if: contains(github.event.pull_request.labels.*.name, 'fuzz')
runs-on: ubuntu-latest-4-cores
permissions:
pull-requests: write
steps:
- name: git checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Install Rust (nightly)
uses: actions-rust-lang/setup-rust-toolchain@fb51252c7ba57d633bc668f941da052e410add48 # v1.13.0
with:
toolchain: nightly-2026-03-13
- name: Install cargo-fuzz
run: cargo install cargo-fuzz --locked
- name: Cache Rust dependencies
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
with:
path: |
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
src/target/
src/chain_parsers/visualsign-solana/fuzz/target/
key: ${{ runner.os }}-cargo-fuzz-${{ hashFiles('src/chain_parsers/visualsign-solana/fuzz/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-fuzz-
${{ runner.os }}-cargo-
- name: install protoc
uses: arduino/setup-protoc@c65c819552d16ad3c9b72d9dfd5ba5237b9c906b # v3.0.0
with:
version: "21.4"
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: free disk space
run: |
sudo swapoff -a
sudo rm -f /swapfile
sudo apt clean
df -h
- name: Run codegen
run: make -C src generated
- name: Fuzz fuzz_transaction_string (30s)
id: fuzz_transaction_string
continue-on-error: true
run: cargo +nightly-2026-03-13 fuzz run fuzz_transaction_string -- -max_total_time=30
working-directory: src/chain_parsers/visualsign-solana/fuzz
- name: Fuzz fuzz_versioned_transaction (30s)
id: fuzz_versioned_transaction
continue-on-error: true
run: cargo +nightly-2026-03-13 fuzz run fuzz_versioned_transaction -- -max_total_time=30
working-directory: src/chain_parsers/visualsign-solana/fuzz
- name: Label PR on fuzz failure
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.pull_request.number }}
run: |
if [ "${{ steps.fuzz_transaction_string.outcome }}" = "failure" ] || [ "${{ steps.fuzz_versioned_transaction.outcome }}" = "failure" ]; then
gh pr edit "$PR_NUMBER" --add-label fuzz-failure || true
else
gh pr edit "$PR_NUMBER" --remove-label fuzz-failure || true
fi
7 changes: 5 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@ on:
branches:
- main
pull_request:
branches:
- main
types: [opened, synchronize, reopened, labeled]

jobs:
ubuntu:
if: |
github.ref == 'refs/heads/main' ||
github.base_ref == 'main' ||
contains(github.event.pull_request.labels.*.name, 'ci')
runs-on: ubuntu-latest-4-cores
steps:
- name: git checkout
Expand Down
61 changes: 61 additions & 0 deletions .github/workflows/proptest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
name: Property Tests

on:
pull_request:
types: [opened, synchronize, reopened, labeled]

jobs:
proptest:
if: contains(github.event.pull_request.labels.*.name, 'proptest')
runs-on: ubuntu-latest-4-cores
permissions:
pull-requests: write
steps:
- name: git checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Install Rust
uses: actions-rust-lang/setup-rust-toolchain@fb51252c7ba57d633bc668f941da052e410add48 # v1.13.0
with:
components: clippy, rustfmt
- name: Cache Rust dependencies
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
with:
path: |
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
src/target/
key: ${{ runner.os }}-cargo-proptest-${{ hashFiles('src/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-proptest-
${{ runner.os }}-cargo-
- name: install protoc
uses: arduino/setup-protoc@c65c819552d16ad3c9b72d9dfd5ba5237b9c906b # v3.0.0
with:
version: "21.4"
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: free disk space
run: |
sudo swapoff -a
sudo rm -f /swapfile
sudo apt clean
df -h
- name: Run codegen
run: make -C src generated
- name: Run proptest tests
id: proptest
continue-on-error: true
run: cargo test -p visualsign-solana
working-directory: src
- name: Label PR on proptest failure
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.pull_request.number }}
run: |
if [ "${{ steps.proptest.outcome }}" = "failure" ]; then
gh pr edit "$PR_NUMBER" --add-label proptest-failure || true
else
gh pr edit "$PR_NUMBER" --remove-label proptest-failure || true
fi
48 changes: 47 additions & 1 deletion docs/contributor-guides/testing-visualizations.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -132,15 +132,49 @@ Solana IDL parsing includes [proptest](https://proptest-rs.github.io/proptest/)-

- `src/chain_parsers/visualsign-solana/tests/fuzz_idl_parsing.rs` — parser-level fuzz and roundtrip tests
- `src/chain_parsers/visualsign-solana/tests/pipeline_integration.rs` — full-pipeline integration tests
- `src/chain_parsers/visualsign-solana/tests/semantic_pipeline.rs` — deterministic tests with real embedded IDLs
- `src/chain_parsers/visualsign-solana/tests/common/mod.rs` — shared test helpers

### Running fuzz tests
### Running proptest tests

```bash
# Run all tests (proptest + semantic + fuzz_idl_parsing)
cargo test -p visualsign-solana

# Default 256 cases per property
cargo test -p visualsign-solana --test fuzz_idl_parsing

# More iterations for deeper fuzzing
PROPTEST_CASES=5000 cargo test -p visualsign-solana --test fuzz_idl_parsing

# Semantic tests only (real embedded IDLs)
cargo test -p visualsign-solana --test semantic_pipeline
```

### Running cargo fuzz targets (libFuzzer)

The `fuzz/` directory contains [libFuzzer](https://llvm.org/docs/LibFuzzer.html) targets that feed arbitrary bytes into the full visualsign-solana stack. These require a nightly toolchain and `cargo-fuzz`:

```bash
cargo install cargo-fuzz --locked

# Run a fuzz target for 30 seconds (same as CI)
cd src/chain_parsers/visualsign-solana/fuzz
cargo +nightly fuzz run fuzz_transaction_string -- -max_total_time=30
cargo +nightly fuzz run fuzz_versioned_transaction -- -max_total_time=30
```
Comment thread
shahan-khatchadourian-anchorage marked this conversation as resolved.

Available targets:

| Target | Entry point | What it exercises |
|--------|-------------|-------------------|
| `fuzz_transaction_string` | `transaction_string_to_visual_sign` | base64/hex decoding, transaction deserialization, IDL dispatch |
| `fuzz_versioned_transaction` | `versioned_transaction_to_visual_sign` | bincode deserialization, versioned transaction path, address table lookups |

When a crash is found, libFuzzer writes a reproducer to `artifacts/`. Reproduce it with:

```bash
cargo +nightly fuzz run <target> artifacts/<target>/crash-<hash>
```

### Testing against real IDLs
Expand Down Expand Up @@ -177,6 +211,18 @@ Both kinds complement each other: concrete roundtrips pin down known-good behavi
4. Run the tests — if proptest finds a failure, it saves a regression seed to `.proptest-regressions`
5. Commit the `.proptest-regressions` file so the failing case is reproduced in CI

### CI workflows

Tests are triggered by adding labels to a PR:

| Label | Workflow | What runs |
|-------|----------|-----------|
| `proptest` | `proptest.yml` | `cargo test -p visualsign-solana` |
| `fuzz` | `fuzz.yml` | Both libFuzzer targets for 30 seconds each |
| `ci` | `main.yml` | Full build, lint, and test suite |

If a fuzz target crashes, the `fuzz-failure` label is added to the PR. If a proptest fails, the `proptest-failure` label is added. These labels are removed automatically on a clean run.

## Validation checklist

Before submitting your visualization:
Expand Down
4 changes: 0 additions & 4 deletions src/chain_parsers/visualsign-solana/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,6 @@
debug/
target/

# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Cargo.lock

# These are backup files generated by rustfmt
**/*.rs.bk

Expand Down
4 changes: 4 additions & 0 deletions src/chain_parsers/visualsign-solana/fuzz/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
target
corpus
artifacts
coverage
Loading
Loading