From f49ad0d7b6ef784a678a1b723fba528fa4aa89b6 Mon Sep 17 00:00:00 2001 From: Renn F Date: Thu, 15 Oct 2026 12:54:36 +0200 Subject: [PATCH 1/3] release(2.0.0): engine routing parity, response pass before the flush --- CHANGELOG.md | 37 +++++++++++++++++++++++++++++++++++++ docs/release-notes.md | 37 +++++++++++++++++++++++++++++++++++++ pyproject.toml | 2 +- 3 files changed, 75 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 996b232..37377fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,43 @@ Release Notes ___ +v2.0.0 (2026-10-15) +------------------- + +Engine routing parity with fastapi-guard, response pass before the flush (v2.0.0) +--------------------------------------------------------------------------------- + +### Breaking changes + +- **`SecurityMiddleware.apply_pre_flight_headers` is removed** (#39, closes #38). It was the reimplemented path that set security and CORS headers before the handler ran. Security headers, CORS and return-rule effects are now applied by the engine response pass in `SecurityHandler.finish()`, and blocked responses carry CORS only, like fastapi-guard. +- **Upgrade action** - Delete any call to `middleware.apply_pre_flight_headers(...)` from your own handlers or subclasses. Subclass `SecurityHandler` and nothing else is needed. +- **`SecurityHandler.finish()` returns a future.** It returns an awaitable like Tornado's own `finish()`, so `await self.finish()` and a bare `self.finish()` both work, and a second call returns the same pending future. +- **The `guard-core` floor moves from `>=4.0.0` to `>=4.1.0`**, the first release with the engine APIs this adapter now uses. +- **A request with no client address is now answered with `403`** under the default `fail_secure=True`. It used to pass through. Set `fail_secure=False` to keep the old behavior. + +### Fixed + +- **The engine response pass now runs in `finish()` before the flush** instead of in `on_finish` after the response was sent. `custom_response_modifier`, the security headers, CORS and return-rule effects now reach the client, and body-based return rules see the buffered body. Streamed responses that call `flush()` before `finish()` already have their headers on the wire, so the pass observes them (metrics, return rules over the buffered body) but cannot change them. +- **Passthrough and the route all-checks bypass go through the engine `BypassHandler`.** Excluded paths are scoped, so bans and IP rules still apply to them, and a bypassed route calls the real handler method with the modifier applied. +- **Blocked, preflight and bypass responses no longer emit request metrics** and skip the response pass. Excluded paths still reach it. +- **Global behavioral return rules now run.** +- **A Redis failure during initialization now returns `503` with `Retry-After`**. + +### Documentation and tests + +- The handler, middleware and adapter docs, the tutorial pages, the agent guidance and the package skill describe the new flow. +- `tests/test_engine_parity.py` runs a real Tornado server and client against the real engine handlers. The tests that asserted the old bypass behavior and the removed pre-flight headers were replaced. + +### Compatibility + +- The detection and dynamic rule fixes in guard-core 4.4.0 reach this adapter by upgrading guard-core (for example `pip install -U guard-core`), with no change to this package. + +### Chore + +- The sponsor button points at the maintainer's Sponsors page, the mkdocs `site_url` drops `/latest/` so canonical URLs resolve, the README markdown lint errors that blocked the docs deploy are fixed and the README was brought to content parity, a CODEOWNERS file was added, the family Discord relay workflow was added, and the `upload-sarif` action was bumped (#29, #30, #31, #32, #34, #36, #37). + +___ + v1.2.1 (2026-10-08) ------------------- diff --git a/docs/release-notes.md b/docs/release-notes.md index 93c2c52..bc3b592 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -10,6 +10,43 @@ Release Notes ___ +v2.0.0 (2026-10-15) +------------------- + +Engine routing parity with fastapi-guard, response pass before the flush (v2.0.0) +--------------------------------------------------------------------------------- + +### Breaking changes + +- **`SecurityMiddleware.apply_pre_flight_headers` is removed** (#39, closes #38). It was the reimplemented path that set security and CORS headers before the handler ran. Security headers, CORS and return-rule effects are now applied by the engine response pass in `SecurityHandler.finish()`, and blocked responses carry CORS only, like fastapi-guard. +- **Upgrade action** - Delete any call to `middleware.apply_pre_flight_headers(...)` from your own handlers or subclasses. Subclass `SecurityHandler` and nothing else is needed. +- **`SecurityHandler.finish()` returns a future.** It returns an awaitable like Tornado's own `finish()`, so `await self.finish()` and a bare `self.finish()` both work, and a second call returns the same pending future. +- **The `guard-core` floor moves from `>=4.0.0` to `>=4.1.0`**, the first release with the engine APIs this adapter now uses. +- **A request with no client address is now answered with `403`** under the default `fail_secure=True`. It used to pass through. Set `fail_secure=False` to keep the old behavior. + +### Fixed + +- **The engine response pass now runs in `finish()` before the flush** instead of in `on_finish` after the response was sent. `custom_response_modifier`, the security headers, CORS and return-rule effects now reach the client, and body-based return rules see the buffered body. Streamed responses that call `flush()` before `finish()` already have their headers on the wire, so the pass observes them (metrics, return rules over the buffered body) but cannot change them. +- **Passthrough and the route all-checks bypass go through the engine `BypassHandler`.** Excluded paths are scoped, so bans and IP rules still apply to them, and a bypassed route calls the real handler method with the modifier applied. +- **Blocked, preflight and bypass responses no longer emit request metrics** and skip the response pass. Excluded paths still reach it. +- **Global behavioral return rules now run.** +- **A Redis failure during initialization now returns `503` with `Retry-After`**. + +### Documentation and tests + +- The handler, middleware and adapter docs, the tutorial pages, the agent guidance and the package skill describe the new flow. +- `tests/test_engine_parity.py` runs a real Tornado server and client against the real engine handlers. The tests that asserted the old bypass behavior and the removed pre-flight headers were replaced. + +### Compatibility + +- The detection and dynamic rule fixes in guard-core 4.4.0 reach this adapter by upgrading guard-core (for example `pip install -U guard-core`), with no change to this package. + +### Chore + +- The sponsor button points at the maintainer's Sponsors page, the mkdocs `site_url` drops `/latest/` so canonical URLs resolve, the README markdown lint errors that blocked the docs deploy are fixed and the README was brought to content parity, a CODEOWNERS file was added, the family Discord relay workflow was added, and the `upload-sarif` action was bumped (#29, #30, #31, #32, #34, #36, #37). + +___ + v1.2.1 (2026-10-08) ------------------- diff --git a/pyproject.toml b/pyproject.toml index a5f1cc7..69669ec 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "tornadoapi_guard" -version = "1.2.1" +version = "2.0.0" description = "Production-ready security middleware for Tornado - IP filtering, rate limiting, penetration detection, and 20+ per-route security decorators." authors = [ {name = "Renzo Franceschini", email = "rennf93@guard-core.com"} From ac7a68baf97f6150c908acd2eeda0fbb17545d74 Mon Sep 17 00:00:00 2001 From: Renn F Date: Thu, 15 Oct 2026 12:57:34 +0200 Subject: [PATCH 2/3] docs(release): drop the finish() return type from the 2.0.0 breaking changes --- CHANGELOG.md | 1 - docs/release-notes.md | 1 - 2 files changed, 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 37377fb..78d7583 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,6 @@ Engine routing parity with fastapi-guard, response pass before the flush (v2.0.0 - **`SecurityMiddleware.apply_pre_flight_headers` is removed** (#39, closes #38). It was the reimplemented path that set security and CORS headers before the handler ran. Security headers, CORS and return-rule effects are now applied by the engine response pass in `SecurityHandler.finish()`, and blocked responses carry CORS only, like fastapi-guard. - **Upgrade action** - Delete any call to `middleware.apply_pre_flight_headers(...)` from your own handlers or subclasses. Subclass `SecurityHandler` and nothing else is needed. -- **`SecurityHandler.finish()` returns a future.** It returns an awaitable like Tornado's own `finish()`, so `await self.finish()` and a bare `self.finish()` both work, and a second call returns the same pending future. - **The `guard-core` floor moves from `>=4.0.0` to `>=4.1.0`**, the first release with the engine APIs this adapter now uses. - **A request with no client address is now answered with `403`** under the default `fail_secure=True`. It used to pass through. Set `fail_secure=False` to keep the old behavior. diff --git a/docs/release-notes.md b/docs/release-notes.md index bc3b592..4bf1dca 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -20,7 +20,6 @@ Engine routing parity with fastapi-guard, response pass before the flush (v2.0.0 - **`SecurityMiddleware.apply_pre_flight_headers` is removed** (#39, closes #38). It was the reimplemented path that set security and CORS headers before the handler ran. Security headers, CORS and return-rule effects are now applied by the engine response pass in `SecurityHandler.finish()`, and blocked responses carry CORS only, like fastapi-guard. - **Upgrade action** - Delete any call to `middleware.apply_pre_flight_headers(...)` from your own handlers or subclasses. Subclass `SecurityHandler` and nothing else is needed. -- **`SecurityHandler.finish()` returns a future.** It returns an awaitable like Tornado's own `finish()`, so `await self.finish()` and a bare `self.finish()` both work, and a second call returns the same pending future. - **The `guard-core` floor moves from `>=4.0.0` to `>=4.1.0`**, the first release with the engine APIs this adapter now uses. - **A request with no client address is now answered with `403`** under the default `fail_secure=True`. It used to pass through. Set `fail_secure=False` to keep the old behavior. From e03af2880790ff04772ac2a036b9866d752924da Mon Sep 17 00:00:00 2001 From: Renn F Date: Thu, 15 Oct 2026 14:32:25 +0200 Subject: [PATCH 3/3] build(deps): require guard-core>=4.4.0 guard-core 4.4.0 is on PyPI, so the floor moves up and upgrading this adapter brings the engine fixes. The release notes say so instead of asking users to upgrade guard-core separately. --- CHANGELOG.md | 4 ++-- docs/release-notes.md | 4 ++-- pyproject.toml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 78d7583..a83a875 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ Engine routing parity with fastapi-guard, response pass before the flush (v2.0.0 - **`SecurityMiddleware.apply_pre_flight_headers` is removed** (#39, closes #38). It was the reimplemented path that set security and CORS headers before the handler ran. Security headers, CORS and return-rule effects are now applied by the engine response pass in `SecurityHandler.finish()`, and blocked responses carry CORS only, like fastapi-guard. - **Upgrade action** - Delete any call to `middleware.apply_pre_flight_headers(...)` from your own handlers or subclasses. Subclass `SecurityHandler` and nothing else is needed. -- **The `guard-core` floor moves from `>=4.0.0` to `>=4.1.0`**, the first release with the engine APIs this adapter now uses. +- **The `guard-core` floor moves from `>=4.0.0` to `>=4.4.0`**, which carries the engine APIs this adapter now uses (first shipped in 4.1.0) and the guard-core 4.4.0 detection and dynamic rule fixes. - **A request with no client address is now answered with `403`** under the default `fail_secure=True`. It used to pass through. Set `fail_secure=False` to keep the old behavior. ### Fixed @@ -31,7 +31,7 @@ Engine routing parity with fastapi-guard, response pass before the flush (v2.0.0 ### Compatibility -- The detection and dynamic rule fixes in guard-core 4.4.0 reach this adapter by upgrading guard-core (for example `pip install -U guard-core`), with no change to this package. +- The `>=4.4.0` floor means upgrading tornadoapi-guard also brings the guard-core 4.4.0 detection and dynamic rule fixes (Cookie header scanned per pair, the per-request scan budget, the semantic-only header opt-out and dynamic rule versions applied over the base config). ### Chore diff --git a/docs/release-notes.md b/docs/release-notes.md index 4bf1dca..e5d2d14 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -20,7 +20,7 @@ Engine routing parity with fastapi-guard, response pass before the flush (v2.0.0 - **`SecurityMiddleware.apply_pre_flight_headers` is removed** (#39, closes #38). It was the reimplemented path that set security and CORS headers before the handler ran. Security headers, CORS and return-rule effects are now applied by the engine response pass in `SecurityHandler.finish()`, and blocked responses carry CORS only, like fastapi-guard. - **Upgrade action** - Delete any call to `middleware.apply_pre_flight_headers(...)` from your own handlers or subclasses. Subclass `SecurityHandler` and nothing else is needed. -- **The `guard-core` floor moves from `>=4.0.0` to `>=4.1.0`**, the first release with the engine APIs this adapter now uses. +- **The `guard-core` floor moves from `>=4.0.0` to `>=4.4.0`**, which carries the engine APIs this adapter now uses (first shipped in 4.1.0) and the guard-core 4.4.0 detection and dynamic rule fixes. - **A request with no client address is now answered with `403`** under the default `fail_secure=True`. It used to pass through. Set `fail_secure=False` to keep the old behavior. ### Fixed @@ -38,7 +38,7 @@ Engine routing parity with fastapi-guard, response pass before the flush (v2.0.0 ### Compatibility -- The detection and dynamic rule fixes in guard-core 4.4.0 reach this adapter by upgrading guard-core (for example `pip install -U guard-core`), with no change to this package. +- The `>=4.4.0` floor means upgrading tornadoapi-guard also brings the guard-core 4.4.0 detection and dynamic rule fixes (Cookie header scanned per pair, the per-request scan budget, the semantic-only header opt-out and dynamic rule versions applied over the base config). ### Chore diff --git a/pyproject.toml b/pyproject.toml index 69669ec..75c5282 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,7 +36,7 @@ keywords = [ ] dependencies = [ "tornado", - "guard-core>=4.1.0", + "guard-core>=4.4.0", ] [project.urls]