Repository navigation
v8.0.0
Lockstep with guard-core 4.0.0: log_activity assertions, timestamp serialisation, unban wiring, throttle docs, hsts None guard (v8.0.0)
- Compatibility (dependency floor, breaking for anyone pinned below 4.0.0) -
guard-corefloor moves from>=3.14.0to>=4.0.0inpyproject.toml, no upper bound. guard-core 4.0.0 carries breaking changes of its own (grammar-based secret redaction,require_headers()now enforces an exact value match for any configured value other than"required",excluded_detection_headersno longer fully silences a header) which do not require any change in this release's own code or tests, since fastapi-guard'srequire_headers()usage in its examples and tests only ever exercises the presence-only"required"value or sends a header value matching what is configured, and neither fastapi-guard's code nor its tests setexcluded_detection_headers. See the guard-core 4.0.0 changelog for the full engine-side list. - Requires (lockstep) - fastapi-guard 8.0.0 tracks guard-core 4.0.0. guard-core 4.0.0 is not yet published to PyPI as of this release commit; CI resolves
guard-core>=4.0.0fresh from PyPI (uv.lockis gitignored) and will fail until it is. This release is held locally, matching the pattern set by earlier lockstep releases, until guard-core 4.0.0 ships. - Tests -
test_cloud_ip_blocking_with_loggingandtest_passive_mode_penetration_detection(tests/test_middleware/test_security_middleware.py) pinned the fulllog_activity()call viaassert_any_call, which broke against guard-core >=3.16.0's addedon_block/sensitive_headers/sensitive_params/sensitive_body_fieldskeyword arguments. Both now check only the kwargs each test cares about as a subset of the actual call (assert_log_activity_called_with), tolerating any further keyword arguments guard-core adds. - Fixed (examples) -
http_exception_handlerandgeneral_exception_handler(examples/advanced_app/app/main.py) dumpedErrorResponsewithmodel_dump(), leavingtimestampas a rawdatetimethatJSONResponsecannot encode, turning every error response (for example/behavior/return-monitor/404) into an unhandled 500. Both now usemodel_dump(mode="json"). - Fixed (examples) -
/admin/unban-ip(examples/advanced_app/app/routes/admin.py) only logged the unban and never called guard-core's IP ban manager, so a banned IP stayed banned. The route now callsip_ban_manager.unban_ip(ip). - Documentation (examples) -
action="throttle"only logs the violation; guard-core never blocks or delays the request for it. Corrected the/behavior/suspicious-frequencyand/behavior/behavior-rulesroute descriptions and dropped the fabricated429response entries that promised otherwise, and corrected the matching lines indocs/tutorial/decorators/behavioral.mdanddocs/api/behavior-manager.md. - Documentation (examples) -
/behavior/usage-monitor'sresponsesentry named a"block"action that does not exist in guard-core (the route usesaction="log"and never returns 429); the entry is removed.alertwas documented as sending a notification; it is a critical-level log call, same as any other action's telemetry event. Corrected inexamples/advanced_app/app/routes/behavioral.pyanddocs/api/behavior-manager.md. - Fixed -
SecurityMiddleware._configure_security_headers(guard/middleware.py) calledheaders_config.get("hsts", {}).get("max_age"), which raisedAttributeErroron every request whensecurity_headers={"hsts": None, ...}was passed explicitly, since.get("hsts", {})returnsNone, not{}, for a key present with an explicitNonevalue. Now falls back to{}the same way guard-core's ownsecurity_headers_handlertreats a missinghstsblock. guard-core 4.0.0 separately fixes the same class of bug on its own singleton (a stalehsts/csp/corsconfiguration surviving a reconfigure), so this guard is defense in depth against both the old and the fixed guard-core behavior. - Security -
guard_websocketandmake_guard_websocket(guard/websocket.py) ran only the IP-ban and rate-limit checks on a WebSocket handshake; an attack riding in the handshake's headers, cookies, query string or path was never detected and never logged. The handshake is now scanned the same way an HTTP request is scanned, through guard-core's ownSuspiciousActivityCheck, honouringenable_penetration_detection,passive_mode,exclude_pathsand the whitelist and auto-ban rules already in place; a detected attack in active mode closes the connection beforeaccept()with the newWS_CLOSE_SUSPICIOUS_ACTIVITYclose reason (code1008, collected inWS_CLOSE_REASONS), logs and emits the same event andon_blockpayload the HTTP pipeline emits, and redacts sensitive header, query and cookie values exactly as the HTTP pipeline does; passive mode logs and emits without closing the connection.
What's Changed
- test: assert guard-core 3.15.0 redis_fail_open semantics by @rennf93 in #127
- ci: issue-first workflow and Discord contact points by @rennf93 in #125
- build(deps): bump actions/github-script from 7 to 9 by @dependabot[bot] in #128
- release(v8.0.0): lockstep with guard-core 4.0.0, example and middleware fixes by @rennf93 in #130
Full Changelog: 7.8.2...8.0.0