1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
[]
# Published to crates.io as `eggrd` ("edgeguard" is taken by an unrelated crate). The binary and
# library keep the name `edgeguard` (see [lib]/[[bin]] below), so the CLI, env vars (EDGEGUARD_*),
# the /__edgeguard/* namespace, and `use edgeguard::` in tests/benches are all unchanged — only the
# crates.io package id differs. Install with `cargo install eggrd` (installs the `edgeguard` binary).
= "eggrd"
= "0.1.4"
= "2021"
= "A drop-in Rust edge proxy that gives any app a secure front door: auth, rate limiting, and hardened response headers, with zero changes to the upstream app."
= "Apache-2.0"
= "https://github.com/lucheeseng827/eggrd"
= "README.md"
= ["proxy", "reverse-proxy", "security", "waf", "rate-limit"]
= ["web-programming::http-server", "network-programming", "command-line-utilities"]
# Keep the published package lean: ship the crate + its config reference + benches, not the load-test
# rig, the detached wasm worker, docs, or deploy examples.
# `ee/` is the PRIVATE control plane (its own workspace) — it must never be packaged into the
# public `eggrd` crate. Keep it first; the rest just trims the published tarball.
= ["ee/", "loadtest/", "worker/", "docs/", "examples/", "tests/", ".github/", ".ossync.yaml"]
# Package id is `eggrd`, but the compiled artifacts stay `edgeguard` so nothing downstream renames.
[]
= "edgeguard"
= "src/lib.rs"
[[]]
= "edgeguard"
= "src/main.rs"
[]
= { = "1", = ["full"] }
= "0.7"
= { = "1", = ["client", "http1", "server"] }
= { = "0.1", = ["client", "client-legacy", "http1", "server", "server-auto", "tokio"] }
= "0.1"
= "1"
= "0.6"
= "0.22"
= { = "1", = ["derive"] }
= "1"
= "0.8"
# WAF-lite input inspection: the built-in SQLi/XSS/path-traversal heuristics and the
# operator-supplied `[[waf.rules]]` deny patterns. The `regex` crate matches in linear time
# and rejects backreferences/lookaround, so a user-supplied pattern can't trigger catastrophic
# backtracking (ReDoS) — a safety property we rely on for the configurable rules.
= "1"
# JWT verification (HS*/RS*/ES*/PS*/EdDSA) and JWKS parsing.
= "9"
# JWKS fetch over HTTPS. `rustls-tls` avoids a system OpenSSL dependency; default features
# (native-tls, gzip, …) are off — a plain GET is all the JWKS client needs.
= { = "0.12", = false, = ["rustls-tls", "json"] }
# Distributed (shared-store) rate limiter for multi-replica deployments: a Redis-backed GCRA
# store (`ratelimit.store = "redis"`). `tokio-comp` for async, `connection-manager` for
# auto-reconnect, `tokio-rustls-comp` so `rediss://` TLS uses rustls (no system OpenSSL),
# matching the rest of the crate. Only used when the distributed limiter is enabled.
= { = "1", = ["tokio-comp", "connection-manager", "tokio-rustls-comp"] }
# Lock-free atomic swap of the live policy, so config hot-reload never blocks the request
# path nor drops in-flight connections.
= "1"
# Watch the config file for changes (hot-reload).
= "6"
# TLS termination. `ring` pins a single crypto provider so the rustls config is deterministic
# regardless of which provider other crates pull in.
= { = "0.23", = ["ring"] }
= "0.26"
= "2"
# Adapt the axum router onto a manual hyper connection when terminating TLS ourselves.
= { = "0.5", = ["util"] }
# ACME / Let's Encrypt automatic certificates (HTTP-01), and CSR/key generation for it.
= "0.7"
= "0.13"
= "0.1"
= { = "0.3", = ["json", "env-filter"] }
= "1"
# `std` pulls in `password-hash`'s getrandom-backed `OsRng` for the `--hash` helper's
# salt generation (verification works without it; salting a fresh hash needs an RNG).
= { = "0.5", = ["std"] }
# Process-group signaling in the supervisor is Unix-only.
[]
= "0.2"
# Micro-benchmark harness for the request-path hot spots (auth gate, WAF regex eval, response
# hardening, config parsing). Macro/throughput load testing lives out-of-process under
# `loadtest/` (k6 + docker-compose); these criterion benches isolate the per-call cost of the
# pure-Rust pipeline stages that the macro test can only measure end-to-end. See docs/TESTPLAN.md.
[]
= { = "0.5", = ["html_reports"] }
[[]]
= "auth"
= false
[[]]
= "waf"
= false
[[]]
= "response"
= false
[]
= 3
= "thin"
= true