Files
doh-forwarder/DEVELOP.md

3.6 KiB

DEVELOP.md — Development Rules & Tracking

Quick Start

# Prerequisites
rustup show            # Rust 1.80+
cargo install cargo-watch

# Run locally
cargo run -- --config config/default.toml

# Run with auto-reload
cargo watch -x run

# Run tests
cargo test

# Lint
cargo clippy -- -D warnings
cargo fmt --check

Development Rules

Code Quality

  1. No warnings. All code must compile with zero warnings. CI treats warnings as errors (-D warnings).
  2. Format before commit. Run cargo fmt — CI checks formatting.
  3. Clippy clean. Run cargo clippy -- -D warnings — CI checks lints.
  4. Tests required. Every new module/function must have unit tests. Public API changes require integration tests.
  5. Doc comments. All public items (pub fn, pub struct, pub enum) must have /// doc comments.

Git Workflow

  1. Branch naming: <type>/<short-description>
    • feat/dns-cache, fix/ttl-overflow, docs/readme, chore/ci-update
  2. Commit messages: Conventional Commits format
    • feat: add DNS response cache
    • fix: handle truncated UDP responses
    • docs: update plan.md
  3. PR required. All changes go through a pull request. No direct pushes to main.
  4. Squash merge. PRs are squash-merged into main.
  5. CI must pass. Lint, test, and build must succeed before merge.

Architecture Rules

  1. No panics in production code. Use Result<T, E> everywhere. unwrap() only in tests.
  2. Structured errors. Define error types per module using thiserror. Use anyhow only in main.rs.
  3. Async everywhere. All I/O is async (Tokio). No blocking calls in async context.
  4. Config-driven. No hardcoded values. All tunables come from config file or env vars.
  5. Dependency injection. Accept traits, not concrete types. Makes testing easy.

Testing Rules

  1. Unit tests in the same file (#[cfg(test)] mod tests { ... }).
  2. Integration tests in tests/ directory.
  3. Test naming: test_<what>_<condition>_<expected> — e.g., test_cache_expired_entry_returns_miss.
  4. No external dependencies in unit tests. Mock upstream resolvers.
  5. Integration tests may spin up the full server on a random port.

Security Rules

  1. No secrets in code. Use env vars or config files (gitignored).
  2. Validate all input. DNS queries from the network are untrusted — validate lengths, offsets, labels.
  3. Timeouts on all upstream calls. Never hang indefinitely.
  4. Rate limiting. Protect against abuse from a single IP.
  5. Dependency audit. Run cargo audit in CI.

Commit Checklist

Before pushing, verify:

  • cargo fmt --check passes
  • cargo clippy -- -D warnings passes
  • cargo test passes
  • New code has tests
  • Public items have doc comments
  • No unwrap() outside of tests
  • Config values are externalized (not hardcoded)

Milestone Tracking

See docs/plan.md for the full project plan and milestone checklist.

Milestone Status
M1 — Core Forwarding Done
M2 — Multiple Upstreams & Config Done
M3 — Local DNS Listener 🔲 Not started
M4 — Caching 🔲 Not started
M5 — Observability 🔲 Not started
M6 — Blocking & Filtering 🔲 Not started
M7 — Production Hardening 🔲 Not started

Useful Commands

# Build release binary
cargo build --release

# Run with specific log level
RUST_LOG=debug cargo run

# Generate and open docs
cargo doc --open

# Dependency audit
cargo install cargo-audit
cargo audit

# Watch tests
cargo watch -x test