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
8 changes: 4 additions & 4 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ Tornado is async, so this adapter imports `guard_core.*` directly (the Flask and
### Package Components

- **`tornadoapi_guard/__init__.py`** - Re-exports items from `guard_core` so users can `from tornadoapi_guard import SecurityConfig, SecurityDecorator, ...` without knowing about guard-core. Also exports `SecurityMiddleware` and `SecurityHandler`, and the adapter classes `TornadoGuardRequest`, `TornadoGuardResponse`, `TornadoResponseFactory`, `apply_guard_response`, `unwrap_response`.
- **`tornadoapi_guard/middleware.py`** - `SecurityMiddleware`, the orchestrator. It builds the `SecurityCheckPipeline` from the config, runs pre-processing (bypass handling, route resolution, the 17 checks) and post-processing (metrics, logging), applies CORS/pre-flight headers, and exposes `set_decorator_handler` so the pipeline can be derived from registered route config.
- **`tornadoapi_guard/handler.py`** - `SecurityHandler(RequestHandler)`. Wrap handler classes that should be guarded: `prepare()` runs pre-flight headers, pre-processing, CORS preflight handling, and applies a blocking response via `apply_guard_response`; `on_finish()` schedules post-processing as a background task.
- **`tornadoapi_guard/middleware.py`** - `SecurityMiddleware`, the orchestrator. It builds the `SecurityCheckPipeline` from the config, runs pre-processing exactly like fastapi-guard's `dispatch` (CORS preflight, engine passthrough and route bypass handlers, route resolution, the 17 checks) and the post-processing response pass (return rules, metrics, security headers, CORS, modifier), and exposes `set_decorator_handler` so the pipeline can be derived from registered route config.
- **`tornadoapi_guard/handler.py`** - `SecurityHandler(RequestHandler)`. Wrap handler classes that should be guarded: `prepare()` runs pre-processing and writes any early response (blocked, preflight, bypass) via `apply_guard_response`; `finish()` is overridden to run the engine response pass before the response is flushed.
- **`tornadoapi_guard/adapters.py`** - Protocol adapters bridging Tornado types to guard-core protocols: `TornadoGuardRequest` (wraps `RequestHandler` + `HTTPServerRequest`), `TornadoGuardResponse` (standalone response container), `TornadoResponseFactory`, plus `apply_guard_response()` (writes a guard response back through the handler) and `unwrap_response()`.

### Public API
Expand All @@ -58,7 +58,7 @@ Tornado's architecture differs from FastAPI/Starlette:
- `RequestHandler` is the main abstraction (not a separate request/response pair)
- `RequestHandler.request` gives `HTTPServerRequest`
- `RequestHandler.prepare()` is the async hook for pre-processing (security pipeline)
- `RequestHandler.on_finish()` is the post-processing hook (metrics, logging)
- `RequestHandler.finish()` is where the response is flushed, so the adapter overrides it to run the response pass first
- No built-in response object; responses are written via `handler.write()` / `handler.finish()`
- `request.remote_ip` for client IP
- `request.headers` for headers (`HTTPHeaders`, case-insensitive)
Expand Down Expand Up @@ -198,7 +198,7 @@ tornadoapi-guard/
├── tornadoapi_guard/ # Adapter package (thin layer over guard-core)
│ ├── __init__.py # Re-exports from guard_core + SecurityMiddleware/SecurityHandler
│ ├── middleware.py # SecurityMiddleware (pipeline orchestration)
│ ├── handler.py # SecurityHandler(RequestHandler) (prepare/on_finish hooks)
│ ├── handler.py # SecurityHandler(RequestHandler) (prepare/finish hooks)
│ ├── adapters.py # Tornado request/response protocol adapters
│ ├── .agents/skills/tornadoapi-guard/ # Package skill (SKILL.md)
│ └── py.typed # PEP 561 marker
Expand Down
8 changes: 4 additions & 4 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ Tornado is async, so this adapter imports `guard_core.*` directly (the Flask and
### Package Components

- **`tornadoapi_guard/__init__.py`** - Re-exports items from `guard_core` so users can `from tornadoapi_guard import SecurityConfig, SecurityDecorator, ...` without knowing about guard-core. Also exports `SecurityMiddleware` and `SecurityHandler`, and the adapter classes `TornadoGuardRequest`, `TornadoGuardResponse`, `TornadoResponseFactory`, `apply_guard_response`, `unwrap_response`.
- **`tornadoapi_guard/middleware.py`** - `SecurityMiddleware`, the orchestrator. It builds the `SecurityCheckPipeline` from the config, runs pre-processing (bypass handling, route resolution, the 17 checks) and post-processing (metrics, logging), applies CORS/pre-flight headers, and exposes `set_decorator_handler` so the pipeline can be derived from registered route config.
- **`tornadoapi_guard/handler.py`** - `SecurityHandler(RequestHandler)`. Wrap handler classes that should be guarded: `prepare()` runs pre-flight headers, pre-processing, CORS preflight handling, and applies a blocking response via `apply_guard_response`; `on_finish()` schedules post-processing as a background task.
- **`tornadoapi_guard/middleware.py`** - `SecurityMiddleware`, the orchestrator. It builds the `SecurityCheckPipeline` from the config, runs pre-processing exactly like fastapi-guard's `dispatch` (CORS preflight, engine passthrough and route bypass handlers, route resolution, the 17 checks) and the post-processing response pass (return rules, metrics, security headers, CORS, modifier), and exposes `set_decorator_handler` so the pipeline can be derived from registered route config.
- **`tornadoapi_guard/handler.py`** - `SecurityHandler(RequestHandler)`. Wrap handler classes that should be guarded: `prepare()` runs pre-processing and writes any early response (blocked, preflight, bypass) via `apply_guard_response`; `finish()` is overridden to run the engine response pass before the response is flushed.
- **`tornadoapi_guard/adapters.py`** - Protocol adapters bridging Tornado types to guard-core protocols: `TornadoGuardRequest` (wraps `RequestHandler` + `HTTPServerRequest`), `TornadoGuardResponse` (standalone response container), `TornadoResponseFactory`, plus `apply_guard_response()` (writes a guard response back through the handler) and `unwrap_response()`.

### Public API
Expand All @@ -58,7 +58,7 @@ Tornado's architecture differs from FastAPI/Starlette:
- `RequestHandler` is the main abstraction (not a separate request/response pair)
- `RequestHandler.request` gives `HTTPServerRequest`
- `RequestHandler.prepare()` is the async hook for pre-processing (security pipeline)
- `RequestHandler.on_finish()` is the post-processing hook (metrics, logging)
- `RequestHandler.finish()` is where the response is flushed, so the adapter overrides it to run the response pass first
- No built-in response object; responses are written via `handler.write()` / `handler.finish()`
- `request.remote_ip` for client IP
- `request.headers` for headers (`HTTPHeaders`, case-insensitive)
Expand Down Expand Up @@ -198,7 +198,7 @@ tornadoapi-guard/
├── tornadoapi_guard/ # Adapter package (thin layer over guard-core)
│ ├── __init__.py # Re-exports from guard_core + SecurityMiddleware/SecurityHandler
│ ├── middleware.py # SecurityMiddleware (pipeline orchestration)
│ ├── handler.py # SecurityHandler(RequestHandler) (prepare/on_finish hooks)
│ ├── handler.py # SecurityHandler(RequestHandler) (prepare/finish hooks)
│ ├── adapters.py # Tornado request/response protocol adapters
│ ├── .agents/skills/tornadoapi-guard/ # Package skill (SKILL.md)
│ └── py.typed # PEP 561 marker
Expand Down
6 changes: 3 additions & 3 deletions docs/api/adapters.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ Snapshots the current state of a `RequestHandler` into a `TornadoGuardResponse`.
- `handler._headers` (Tornado's internal `HTTPHeaders` container) for the accumulated response headers.
- `handler._write_buffer` for the accumulated response body.

Used by `SecurityMiddleware.run_post_processing` to build a response object from a handler that has already written its reply, so that behavioral return rules and metrics collectors can see the actual status / headers / body that went on the wire.
Used by `SecurityMiddleware.run_post_processing` to build a response object from a handler that has already written its reply, so that behavioral return rules and metrics collectors can see the actual status / headers / body before they are flushed to the client. `SecurityHandler.finish()` runs the response pass at that point, so any change the pass makes (security headers, CORS headers, `custom_response_modifier`) is written back onto the handler and reaches the client.

___

Expand Down Expand Up @@ -179,7 +179,7 @@ Writing Custom Hooks
`SecurityConfig` accepts two user-provided callables:

- `custom_request_check(request)` — runs at the end of the security pipeline. Return a `GuardResponse` to short-circuit the request, or `None` to let it through.
- `custom_response_modifier(response)` — runs during post-processing. Receives the built response and may mutate its headers (or construct a new response) before the middleware hands it back.
- `custom_response_modifier(response)` - runs during the response pass in `SecurityHandler.finish()`, before the response is flushed. Receives the response built from the handler (and the pipeline's own blocking responses) and may mutate its headers (or construct a new response); the status, header and body changes reach the client.

Use `TornadoGuardResponse` for return values so that `SecurityMiddleware` can apply headers, CORS, and the custom modifier uniformly. The pattern below mirrors `examples/simple_app/main.py`:

Expand Down Expand Up @@ -227,7 +227,7 @@ ___
Per-handler State
-----------------

`TornadoGuardRequest.state` returns a `SimpleNamespace` that the middleware uses to stash per-request data: the guard request itself, the resolved route config, the extracted client IP, and the request start time. Behavioral hooks, post-processing, and custom validators read from this namespace.
`TornadoGuardRequest.state` returns a `SimpleNamespace` that the middleware uses to stash per-request data: the guard request itself, the resolved route config, the extracted client IP, and the request start time. Behavioral hooks, the response pass, and custom validators read from this namespace.

The storage is backed by a module-level `WeakKeyDictionary` keyed by the handler instance:

Expand Down
Loading
Loading