Over the past several months, we’ve made significant changes to Zebra’s continuous integration and testing infrastructure. For those new to the project, Zebra is the Zcash Foundation’s full-node implementation written in Rust, providing an independent, memory-safe, and consensus-compatible alternative to zcashd.
These improvements make it easier for anyone to fork the repository, test their changes, and contribute to the project—without relying on external services or special permissions.
Why These Changes Matter
Previously, contributing to Zebra meant dealing with several roadblocks:
- Forked repositories couldn’t run most CI tests because they depended on Firebase, external Docker registries, and other services that contributors didn’t have access to
- Test builds were slow and sometimes rebuilt unnecessarily
- Complex configuration made it hard to understand which tests were running and why
- External dependencies added costs and made the CI fragile
We’ve systematically addressed each of these issues.
What We’ve Improved
We have made five notable improvements:
1. CI Now Works on Forks
The biggest change: if you fork Zebra, the CI just works. We removed all dependencies on external services that required special access:
- Documentation now deploys to GitHub Pages instead of Firebase
- All workflows run on standard GitHub infrastructure
- Docker images build directly in GitHub Actions, no longer requiring Google Cloud Platform or Docker Build Cloud
- Removed 19 patch files and 2,900 lines of configuration complexity
We also made Zebra’s internal workflows easier to identify by adding a zfnd- prefix, so it’s clear which workflows are specific to the Zcash Foundation’s infrastructure and which ones will work in your fork.
See our CI/CD architecture documentation →
2. Faster, More Reliable Tests with Nextest
We migrated Zebra’s entire test suite to use cargo-nextest, a modern test runner that offers several advantages:
- Faster execution: Tests run in parallel with smarter scheduling
- Better reliability: Proper timeout handling prevents false failures
- Clearer configuration: All 17 test profiles are defined in .config/nextest.toml instead of scattered across shell scripts
- Simpler workflows: One NEXTEST_PROFILE variable replaces dozens of environment flags
This change eliminated unnecessary rebuilds caused by feature flag mismatches and streamlined how we run different types of tests (full sync, RPC tests, lightwalletd integration, etc.).
See our nextest profiles and test categories →
3. Removed External Build Dependencies
We used to rely on external services to build Docker images because the builds were resource-intensive. This created two problems:
- Contributors couldn’t build images in their forks
- It incurred in significant costs
Now, Docker images build entirely within GitHub Actions using standard infrastructure. We made the builder configurable, so if you fork Zebra, your images will build automatically without any special setup.
The workflow also adapts to your environment—it uses standard GitHub runners in forks and larger runners in the main repository, so contributors aren’t blocked by runner size limitations.
Learn more about our Docker setup →
4. Streamlined Testing and Deployment
We simplified how tests are organized and run:
- Single unified workflow: Instead of building Docker images multiple times across different workflows, we build once and reuse it for all tests.
- Consistent naming: Standardized test names across GitHub workflows, environment variables, and Rust code makes it easier to trace failures and understand what’s being tested.
- Simplified GCP integration: For tests that do run on Google Cloud Platform (in the main repository), we removed the intermediate container layer and use direct instance creation, which improves reliability and logging.
See our workflow organization →5. Better Configuration Management
We replaced the legacy configuration system with a modern layered approach:
- Configure Zebra using ZEBRA_ prefixed environment variables without needing a generated config file
- Simplified Docker entrypoint that doesn’t need to generate TOML files
- Clearer separation between defaults, optional TOML files, and environment overrides
This makes it easier to test different configurations and reduces the complexity of the Docker entrypoint script.
See the configuration documentation →
What This Means for You
Whether you’re a contributor, a community member running your own Zebra node, or an organization building on top of Zebra:
- Fork and test freely: You can fork Zebra and run the full CI suite in your own repository
- Faster feedback: Tests run faster and more reliably, so you get quicker feedback on changes
- Easier debugging: Clearer test names and better logging make it simpler to understand what went wrong when a test fails
- Lower barriers to entry: New contributors don’t need to understand complex external dependencies or request access to special services
What’s Next
We’re not done yet. The improvements we’ve made so far lay the groundwork for even more significant changes coming soon:
Smarter Test Selection
We’re re-architecting how tests are organized and run so you can choose exactly what to test based on your needs:
- Run by test type: Select just unit tests, integration tests, or stateful tests (tests that require a cached blockchain state)
- Run by quality level: Choose between quick smoke tests and comprehensive test suites
- Run what matters: If you’re working on RPC functionality, run just the RPC tests. Working on sync logic? Run only sync-related tests.
This will make the development cycle faster—you won’t need to wait for the entire test suite when you’re only changing a specific component.
Regtest for Faster, More Reliable Testing
We’re considering a shift to using regtest (regression test mode—a local testing environment where blocks can be generated on demand) instead of relying on mainnet or testnet for complex integration tests:
- No sync wait times: Tests won’t need to wait for long mainnet syncs to complete before running
- Predictable test environments: Create custom blockchain states on demand rather than depending on network state
- Faster iteration: Run complex network interactions without the overhead of full blockchain synchronization
This change would make our stateful tests significantly faster and more reliable, especially for testing complex interactions between Zebra and the network.
Workflow Modernization
We’re continuing to refactor our remaining specialized workflows, simplifying our infra-related deployment workflows
These changes will follow the same principles: reduce complexity, remove external dependencies where possible, and make everything work seamlessly in forks.
Continuous Improvement
The work we’ve completed over the past few months demonstrates our commitment to making Zebra easier to work with. We’ll continue to identify bottlenecks, simplify workflows, and improve the contributor experience.
Get Started!
All of these improvements are already live in the main branch. If you’ve been thinking about contributing to Zebra, or if you previously had trouble running tests in your fork, now is a great time to give it another try.
To get started:
Questions or feedback? We’d love to hear about your experience with the new CI setup. Let us know in Discord or open an issue in the Zebra repository.
The Zcash Foundation is committed to transparency and openness with the Zcash community. We’ll continue sharing updates on our engineering work and welcome your feedback and contributions.