Skip to content

ci(fuzz): run fast-check fuzz targets on the ChainSafe fuzz platform - #90

Merged
nazarhussain merged 2 commits into
nh/fuzz-testingfrom
nh/fuzz-platform
Nov 6, 2026
Merged

nazarhussain merged 2 commits into
nh/fuzz-testingfrom
nh/fuzz-platform

Conversation

@nazarhussain

@nazarhussain nazarhussain commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

Packages the fast-check fuzz targets from #41 as a Docker image for the ChainSafe fuzz platform, so they run continuously as one campaign (zapi:round-trip).

Stacked on #41 (which is stacked on #83). Merge those first.

Changes

  • Dockerfile.fuzz (+ .dockerignore): a build stage that downloads Zig 0.16.0 (checksum-verified) and builds test_fuzz_numeric.node with ReleaseSafe and -Dcpu=baseline. The runtime stage is node:24-slim with the addon, the tests and node_modules.
  • tests/fuzz/platform/run-fuzz.ts: the entrypoint, which implements the platform's container contract. It re-runs every *.fuzz.test.ts in a loop (100 000 cases per property by default, a fresh random seed each time) until SIGTERM.
    • A failing property is saved once to $FUZZ_FAILURES/failure-<hash>.json, de-duplicated by test name and shrunk counterexample. The file includes the seed and path for replay. Fuzzing then continues.
    • $FUZZ_METRICS/status is rewritten atomically after each iteration. It reports execs_total, execs_per_second, crashes_total and last_find_timestamp_seconds. There is no coverage or corpus field, because fast-check is not coverage-guided.
    • Counters persist in $FUZZ_STATE/stats.json.
    • A test file that fails to load, or a run with no tests, exits non-zero (an infrastructure failure).
  • .github/workflows/fuzz-image.yml: mirrors lodestar-z's fuzz-image.yml. A build and test job runs with read-only permissions and smoke-tests the image under the platform's restrictions (non-root uid, read-only rootfs, no capabilities, no network, --init). Publishing is manual (workflow_dispatch): a separate publish job, the only one with packages: write, pushes the exact tested image as main (run on main) or branch-<name> (any other branch), plus sha-<short>, and keeps the newest 20 versions. lodestar-z's AFL++-only steps (seed replay, core_pattern, minimize) are omitted; the platform reads none of them.
  • tests/fuzz/README.md: a section on continuous fuzzing.

Verified locally (arm64 Docker, platform restrictions)

  • Runs continuously and stops on SIGTERM with exit 0.
  • The status file is written and updated.
  • Counters resume across restarts.
  • A planted failing property is saved once over about 20 failing iterations.
  • A hidden addon gives FATAL a test suite failed to load and exit 1.

The amd64 build and the workflow itself have not run yet; this PR's CI is their first run.

Follow-ups

  • After merging, publish by running the workflow on main from the Actions tab. Then set the GHCR package zapi-fuzz to public. The platform pulls without credentials.
  • Add the target to group_vars/fuzzer/vars.yml in lodestar-ansible-development:
    - project: zapi
      target: round-trip
      image: ghcr.io/chainsafe/zapi-fuzz:main
      cpu_mhz: 1000
      memory_mb: 1024
      duration: 0
      uid: 60011
      gid: 60011

🤖 Generated with Claude Code

@nazarhussain
nazarhussain merged commit 669e36c into nh/fuzz-testing Nov 6, 2026
2 checks passed
@github-project-automation github-project-automation Bot moved this from In Progress to Done in Lodestar Team Coordination Nov 6, 2026
@nazarhussain
nazarhussain deleted the nh/fuzz-platform branch November 6, 2026 09:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant