Repository navigation
3.0.0
Hardening release routing CORS through the security pipeline.
Companion to guard-core 2.2.0 and guard-agent 2.3.0. Closes the audit's preflight-bypass finding for the Flask adapter.
Breaking change — preflight OPTIONS requests are now subject to the security pipeline.
Pipeline / CORS
_before_requestnow runs the security pipeline for every method includingOPTIONS. Banned IPs, rate-limited clients, and suspicious patterns apply to preflight just like every other request.- Preflight response construction and response-header injection moved to the shared
guard_core.sync.handlers.cors_handler.CorsHandlermodule. - Blocked responses now carry CORS headers when the origin is allowed — cross-origin clients see the real status code instead of an opaque CORS error.
_after_requestinjects CORS headers into normal responses.- The old
_handle_preflightflow is gone; replaced by_attach_cors_to_blockedand_build_flask_preflight_responsehelpers.
Internal — suppression cleanup
The release-wide no-suppression rule applied here too. Removed:
- Every
[[tool.mypy.overrides]] ignore_missing_imports = true/follow_imports = "skip"/disallow_untyped_decorators = falseblock. Replaced with proper stubs (django-stubsif needed), inline-typed packages withpy.typed(redis, guard-core, guard-agent). - Every
# type: ignoremarker in edited files. Replaced withcast(...),MagicMock(spec=...), or properly typed callbacks. - The
[tool.uv.sources] guard-core = { path = ..., editable = true }block from committed pyproject.toml — that's per-developer config, not project metadata. Useuv pip install -e ../guard-coreafteruv syncfor local-dev override.
Configuration
guard-agentadded to dev dependencies. Previously only mentioned in deptry's ignore list, which meant tests exercising agent integration relied on the package being installed by coincidence.
Test coverage
- 214 tests, 100% line + 100% branch coverage across
flaskapi_guard/(376 statements, 70 branches, 0 missed). Zero warnings under-W error.
Compatibility
- Python 3.10–3.14.
- Requires
guard-core>=2.2.0(declared as unconstrainedguard-corein pyproject.toml; documented here for upgrade guidance). guard-agentis a dev dependency; runtime usage remains opt-in viaSecurityConfig.enable_agent=True.
Migration
Before — explicit preflight bypass behavior assumed:
config = SecurityConfig(enable_cors=True, cors_allow_origins=["https://app.example.com"], ...)
FlaskAPIGuard(app, config)
# Preflights short-circuited inside the extension before any check ranAfter — preflight goes through the same checks as every other request:
config = SecurityConfig(
enable_cors=True,
cors_allow_origins=["https://app.example.com"],
cors_allow_methods=["GET", "POST"],
cors_allow_headers=["X-Custom"],
cors_allow_credentials=True,
cors_max_age=600,
)
FlaskAPIGuard(app, config)The cors_* fields drive everything; CORS is configured purely via SecurityConfig and activates inside the FlaskAPIGuard extension. There is no separate configure_cors entry point.
What's Changed
Full Changelog: 2.2.0...2.3.0