Skip to content

Latest commit

 

History

History
175 lines (130 loc) · 4.57 KB

File metadata and controls

175 lines (130 loc) · 4.57 KB

Contributing to sbproxy

Last modified: 2026-05-17

Prerequisites

  • Rust 1.82+ (workspace MSRV, pinned in Cargo.toml)
  • Cargo (comes with Rust)
  • Node.js 18+ (for e2e test backends)
  • cmake (for Pingora's BoringSSL dependency)

Building

# Debug build (fast compilation)
cargo build --workspace

# Release build (optimized)
cargo build --release -p sbproxy

Testing

# Run all unit tests
cargo test --workspace

# Run tests for a specific crate
cargo test -p sbproxy-modules
cargo test -p sbproxy-ai
cargo test -p sbproxy-extension

# Run with output
cargo test -p sbproxy-modules -- --nocapture

# Run a specific test
cargo test -p sbproxy-modules json_transform_set_fields

Running

# Start with a config file
./target/release/sbproxy --config sb.yml

# The config format is YAML:
# proxy:
#   http_bind_port: 8080
# origins:
#   "example.com":
#     action:
#       type: proxy
#       url: http://backend:3000

Project structure

See docs/architecture.md for the full architecture guide.

The project is a Cargo workspace with 20 crates under crates/. Each crate has a single responsibility.

Adding a new module

Built-in module (enum variant)

  1. Choose the module type: action, auth, policy, or transform
  2. Add your config struct to the appropriate file in sbproxy-modules/src/{type}/
  3. Add a new variant to the enum in sbproxy-modules/src/{type}/mod.rs
  4. Update the match arms in *_type(), Debug, and apply()/check() methods
  5. Add a match arm in sbproxy-modules/src/compile.rs for your type name
  6. Write unit tests
  7. Run cargo test --workspace

Example, adding a new policy:

// In sbproxy-modules/src/policy/mod.rs
pub enum Policy {
    // ... existing variants ...
    MyNewPolicy(MyNewPolicy),
    Plugin(Box<dyn PolicyEnforcer>),
}

// In a new file or same file:
#[derive(Debug, Deserialize)]
pub struct MyNewPolicy {
    pub some_field: String,
}

impl MyNewPolicy {
    pub fn from_config(value: serde_json::Value) -> anyhow::Result<Self> {
        Ok(serde_json::from_value(value)?)
    }
    pub fn check(&self) -> bool { true }
}

// In compile.rs:
"my_new_policy" => Ok(Policy::MyNewPolicy(MyNewPolicy::from_config(config.clone())?)),

Third-party plugin (dynamic dispatch)

Out-of-tree crates can register their own actions, auth providers, policies, or transforms via inventory. The proxy discovers them at link time, so no central wiring change is needed.

// In your-crate/src/policy.rs
use sbproxy_plugin::*;

pub struct MyPolicy { /* ... */ }

impl PolicyEnforcer for MyPolicy {
    fn policy_type(&self) -> &'static str { "my_policy" }
    fn enforce(&self, req: &http::Request<bytes::Bytes>, ctx: &mut dyn std::any::Any)
        -> Pin<Box<dyn Future<Output = Result<PolicyDecision>> + Send + '_>>
    {
        Box::pin(async move { Ok(PolicyDecision::Allow) })
    }
}

inventory::submit! {
    PluginRegistration {
        kind: PluginKind::Policy,
        name: "my_policy",
        factory: |config| { /* ... */ },
    }
}

Code style

  • Follow rustfmt defaults
  • Prefer anyhow::Result for fallible functions
  • Use CompactString for short strings (hostnames, IDs)
  • Use SmallVec for small collections (policies, transforms)
  • Write doc comments on all public types and functions

Pre-commit gates

Run all five before pushing. Each one mirrors a required CI gate; if any fails locally, CI will fail too.

Check Command
Format cargo fmt --all -- --check
Build cargo build --workspace
Test cargo test --workspace --release --tests
Clippy cargo clippy --workspace --all-targets -- -D warnings
Docs RUSTDOCFLAGS="-D warnings" cargo doc --workspace --no-deps --document-private-items

Fix the issue before pushing. Do not paper over with #[allow(...)] unless you also write a one-line comment explaining the deliberate exception.

E2E tests

Two suites ship in-tree. Both run against the release binary:

  • e2e/tests/*.rs is the Rust-native suite, driven by cargo test -p sbproxy-e2e --release. One file per feature, typed harness.
  • e2e/conformance/ is the vendored curl + bash conformance suite (93 cases). It is the strictest HTTP wire-protocol harness we ship.
# Run the curl conformance suite (all cases)
./scripts/run-e2e.sh

# Run specific cases
./scripts/run-e2e.sh 01 14 11

See e2e/conformance/HOW-TO-RUN.md for the side-by-side comparison of the two suites.

Benchmarks

# Run all benchmarks
cargo bench --workspace

# Run specific benchmark
cargo bench -p sbproxy-modules -- json_transform