Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Downstream consumers: `axum-guard-rs` re-exports this crate's `GuardLayer`/`with
## Boundary Rules

- **No security logic in this crate.** Detection comes from `guard-core-engine`'s `detect`. Policy values (thresholds, caps) are configuration, not logic.
- **No framework dependencies.** This crate depends on `http`, `http-body`, `http-body-util`, `bytes`, `tower`, and the engine. Never add `axum`, `hyper`, `actix-web`, `rocket`, or a tokio runtime dependency to `[dependencies]`. tokio belongs in `[dev-dependencies]` for tests only.
- **No framework dependencies.** This crate depends on `http`, `http-body`, `http-body-util`, `bytes`, `tower`, and the engine. Never add `axum`, `hyper`, `actix-web`, `rocket`, or a tokio runtime dependency to `[dependencies]`. tokio belongs in `[dev-dependencies]` for tests only. The one exception is the optional `agent` feature, which pulls guard-agent-rs and tokio's `rt` feature to build the telemetry agent from the config (guard-agent-rs depends on the facade, so the facade cannot own that step); the default build has neither. `body_read_timeout` is enforced through a host-supplied timer (`with_body_timer`) for the same reason.
- **No modifications to the engine.** Engine behavior changes are `guard-core-rs` PRs.
- **Fail-secure, always.** A body read error, an engine panic, or a body over the cap must never result in an uninspected passthrough. Failures answer `500` (or `413` for oversize).

Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,16 @@ Unreleased
- `from_security_config_with(config, WiringOptions)` and `from_wiring(Wiring)`: the telemetry agent is injected through the facade's `TelemetryHandler`, which wires the event bus, the request metrics, `agent_stats()` (now reporting `enabled` and `degraded` from the sink), `spawn_dynamic_rules()` (host-started poll loop) and the cloud refresh (per-request `refresh_if_due` at the cloud position plus `refresh_cloud_ip_ranges`)
- The `GuardExclusionScoped` request extension, the `security_bypass` event for all-checks-bypass routes, the global `auth_verifier` as the fallback verifier of a route that carries none (`with_auth_verifier`), and re-exports of `ResponseBits`, `RequestBits`, `SecurityMetric`, `SecurityEvent`, `CustomResponse`, `CloudRefreshScheduler`, `StoreError` and the wiring types
- `GuardConfigError` gains `Cloud`, `Redis` and `Geo` variants
- Live dynamic rules: a layer built from a config reads the stages a rule can change (geo, cloud, blocked user agents, emergency, the penetration toggle, the rate limits and the ban knobs) from the engine's live cell on every request, so a rule-driven change takes effect (`LiveCell`, `LiveContext`, `LiveStages` are re-exported)
- `route_resolution_strict` through the `GuardRouteUnresolved` request extension (`500 Route resolution failed`, a logged `route_unresolved` event under `passive_mode`) and `GuardLayer::with_route_resolution_strict`
- `body_read_timeout` for the request body: `with_body_read_timeout` (installed from the config), `with_body_timer` (the host's timer, `SleepFn`) and the `408 Request body read timed out` answer
- The optional `agent` feature builds the telemetry agent from the `agent_*` config fields (`GuardConfigError::Agent` under `agent_strict`, `agent_stats().degraded` otherwise) and the `redis` feature forwards the facade's Redis backend
- `GuardConfigError::Config`: the config is validated (`SecurityConfig::validate`) before the pipeline is built

### Changed

- The route usage rules (`process_usage_rules`) run after the check pipeline, just before the request is forwarded, as the reference `dispatch` does (they ran first, so a blocked request counted toward a usage threshold), and only for an attributed request
- `from_security_config` rejects a config the validator refuses with `GuardConfigError::Config` instead of reaching the stage constructors (an invalid IP list entry is now reported there)
- `exclude_paths` now uses the engine matcher (prefix on a `/` boundary, percent-decoded, dot-collapsed) and runs the scoped pipeline instead of bypassing everything: bans, the global IP, country and cloud rules and the rate limit still apply to an excluded request, which now also emits request metrics and gets the response pass without return rules
- `from_security_config` goes through the facade `Wiring`: geo country rules, cloud providers, endpoint rate limits, rate-limit auto-ban, the custom request check, the auth verifier, trusted proxies, the config response modifier, `on_error`, `cors_expose_headers`, Redis stores and the telemetry knobs are now installed (previously dropped); country rules without a `geo_ip_handler` or `ipinfo_token` fail closed with `GuardConfigError::Geo`; the detection exclusions block is always installed
- The response modifier runs even when no `ResponseProcessor` is installed, return rules evaluate the response body when the processor asks for it (the body is buffered and re-emitted, a read error answers the fail-secure `500`), and an all-checks-bypass route is forwarded with only the modifier applied (passive mode keeps it in the pipeline)
Expand Down
Loading
Loading