Contribute
Note: This page mirrors CONTRIBUTING.md from the Ferron repository and exists so the old ferronweb.org/contribute URL keeps working after the domain migration. The repository file is the source of truth, and this page may be removed once the migration has settled.
Thank you for helping improve Ferron!
Before you start
- Read the
README.mdfor build and run basics. - Follow the
CODE_OF_CONDUCT.md. - If your change is security-sensitive, report it privately as described in
SECURITY.mdinstead of opening a public issue.
What to contribute
Contributions are welcome across:
- bug fixes
- new features
- performance improvements
- tests
- documentation updates
Development setup
- Fork the repository and clone your fork.
- Create a branch from
develop-3.x(this is the default development branch for Ferron 3 work; CI workflows filter on it and the 3.x docs site syncs from it). - Make your changes in focused commits.
Repository layout
Ferron 3 is a Rust workspace (resolver “2”). Key directories include:
core/: the Ferron corebin/: thin wrapper aroundferron-entrypointentrypoint/: the entrypoint binary that wires all modulesmodules/*: where individual module crates are locatedtypes/*: shared types that can be used by modulese2e/: E2E tests via testcontainers (requires Docker andprotoc)docs/: user-facing docs; sidebar indocs/links.jsondoctest/: setup for testing Ferron configurations in doc examplesutils/: CLI utilities (fmt,kdl2ferron,passwd,precompress,serve)
Build and check locally
Run from the repository root unless noted:
| Command | Purpose |
|---|---|
cargo build --workspace | Build all workspace crates |
cargo test --workspace | Run unit and inline tests |
cargo test -p <crate> | Run tests for a single crate |
cargo fmt --all --check | Check formatting (the repo uses default rustfmt settings, no .rustfmt.toml) |
cargo clippy --workspace --all-targets -- -D warnings | Lint; warnings fail the check |
cargo shear | Check for unused dependencies (also runs in CI) |
cargo run --manifest-path doctest/Cargo.toml | Test Ferron configurations in doc examples |
cd e2e && cargo test | Run E2E tests (needs Docker and protoc; build the test image first, see below) |
rumdl fmt docs && rumdl check --fix docs | Format and lint docs Markdown (requires rumdl) |
npx aislop scan | Scan for possible AI-generated issues (false positives are possible; requires npm) |
just automates packaging and related tasks. Run just --list to see available recipes.
Run the server from source
cargo run -p ferron -- run -c ferron.conf # start
cargo run -p ferron -- validate -c ferron.conf # validate config
cargo run -p ferron -- doctor -c ferron.conf # best-practice check
cargo run -p ferron -- version # version and build infoSee docs/ for details and more commands.
Testing structure
There are three tiers:
-
Inline unit tests:
#[cfg(test)] mod testsinside source files. Run them withcargo test --workspaceorcargo test -p <crate>. -
E2E tests:
e2e/tests/, each file declared as[[test]]ine2e/Cargo.toml. They usetestcontainersandreqwestand need a Docker daemon andprotocinPATH. Build the test image first:docker build -f e2e/Dockerfile.test -t e2e-test-ferron:latest . cd e2e && cargo testIf your change affects runtime behavior, networking, modules, container packaging, or config parsing, run the E2E suite.
-
Fuzz:
fuzz/uses nightlycargo-fuzzand is excluded from the main workspace. Run from insidefuzz/(list files infuzz/fuzz_targets/for available targets):cargo +nightly fuzz run $FUZZ_TARGETDictionaries and seed corpora live in
fuzz/dictionaries/andfuzz/corpus/.
Benchmarks live in modules/http-server/benches/ (Criterion, gated on features = ["bench"] on the ferron-http-server crate).
Runtime note
Ferron uses a dual runtime: primary threads run zincio (one per CPU, pinned, optional io_uring) and a secondary runtime is tokio. Most request handling runs on the primary runtime, so when you write HTTP server modules, prefer zincio functions over tokio equivalents.
Code conventions
- When you leave a stub implementation, add a
TODOmarker in the comment that explains the stub. - When your stub implementation is intentional (because of some constraint that prevents de-stubbing), add a
STUBmarker in the comment that explains why. - When you leave a comment about a known issue, add a
FIXMEmarker.
Documentation expectations
If behavior, configuration, CLI output, installation steps, or defaults change, update documentation in the same pull request.
-
Main docs live in
docs/. -
If you add or rename doc pages, update
docs/links.json. -
If you change configuration directives, update the matching pages under
docs/configuration/and validate with:cargo run -p ferron -- validate -c ferron.conf cargo run --manifest-path doctest/Cargo.toml -
Keep examples and command snippets aligned with the code and scripts in this repository.
-
Config examples use
.confor.ferronfile extensions. If you show an invalid configuration on purpose, prepend# INVALIDto exactly the first line. For the full docs style guide, see docs/README.md.
Every feat: or fix: commit must include updates to documentation (under docs/), the changelog (CHANGELOG.md, unless the change is a subtle implementation detail with no user-visible effect), and E2E tests (e2e/tests/, when applicable). This keeps docs from drifting and keeps changes verified. The docs: commit type is the exception: it may update documentation alone without code or tests.
Optional local docs linting/formatting (same tool used in CI):
rumdl fmt docs
rumdl check --fix docsFor other guidelines for writing documentation, see docs/README.md.
Cross-compilation and Docker builds
- Linux cross-builds use
cross-build/build.sh(PGO by default) on Linux hosts andcrossotherwise. See cross-build/README.md. Non-crossbuilds requirebindgen-cli. - Docker images use PGO builds (
Dockerfiledistroless and musl,Dockerfile.alpine,Dockerfile.debianglibc-slim). Build a no-PGO variant with--build-arg NOPGO=1.
Pull request guidelines
- Open pull requests against
develop-3.xby default. - Use a clear title and description explaining:
- what changed
- why it changed
- how you validated it (commands you ran)
- Link related issues when applicable.
- Keep pull requests focused; separate unrelated changes.
- Ensure CI is green before requesting review.
Commit guidance
- Commit messages follow Conventional Commits (
feat:,fix:,docs:,test:,refactor:,chore:). - Keep commit messages descriptive and scoped.
- Avoid mixing refactors, behavior changes, and docs-only updates in one commit when possible.
- Do small, incremental commits that are easy to review, instead of large, monolithic commits.
- Update
CHANGELOG.mdunder the unreleased section for user-facingfeat:andfix:changes. Docs-only changes and subtle implementation details are exempt. New entries start with a “Breaking changes” section when applicable, followed by categorized sections (seeCHANGELOG.mdfor the current layout). Use a bold inline header for each bullet.
AI policy
- AI coding agents are allowed to assist with code generation and documentation (for example when dealing with repetitive tasks or boilerplate code). For improved code quality and guidance, tell the AI agent to read this file (
CONTRIBUTING.md) before making any changes. - Commit messages with AI assistance should have
Assisted-by: AgentName:ModelVersionin the footer (for example when using Claude Opus 4.8 on Claude Code, useAssisted-by: Claude:Opus-4.8). AI-powered autocomplete is exempt from this requirement. - Autonomous AI agents opening pull requests (and issues) aren’t allowed. Any such activity will be detected. This is to make sure an actual human is responsible for code changes, not some automated system.
- Bulk (high volume in short time) AI-generated code and commits are discouraged. This is to make sure the code quality remains high and maintainable.
- The repository has an
aislopCI/CD workflow that detects low-quality AI-generated code (aka “AI slop”) usingnpx aislop ci.
Questions and discussion
- Open a GitHub issue for bugs or feature requests.
- For general help and discussion, use the project community channels listed on the Ferron website.