v0.9.0 — Self-host production hardening (auth, CSRF, rate limit)
Added — Self-host production hardening (opt-in auth, CSRF, rate limiting)
Answers the valid P0 findings from a production-readiness audit (no auth/HTTPS/CSRF/rate-limit = blockers for exposing OpenCLAWN to the internet). Everything defaults off (OPENCLAWN_AUTH_TOKEN unset) — the old no-login behavior still works for localhost/VPN use. No new dependencies: auth uses stdlib hmac/secrets instead of Starlette's SessionMiddleware (which needs itsdangerous), and rate limiting is in-memory (single-process is enough for single-user, per the project's design).
security/auth.py— single-user shared-secret login, HMAC-signed session cookie (7-day expiry, constant-time verification), CSRF token generation.security/rate_limit.py— sliding-window limiter for/chat/streamand/converse/stream(default 20 req/60s), independent of whether auth is enabled.web/main.py— auth+CSRF+rate-limit middleware,/login+/logoutroutes, custom 404/500 exception handlers (no leaked stack traces), startup health check (logs Ollama/API-key/auth status without blocking boot),/healthnow reportsollama/cloud_keys/auth_enabled.- New
login.html/404.html/500.htmltemplates + a Sign out button in the sidebar (shown only when auth is enabled). Caddyfile.examplefor a TLS reverse proxy, plus adocker-compose.ymlhealthcheck (stdliburllib, notcurl— avoids adding a package to the slim image).- Documentation (README,
docs/security.md,docs/web.md,docs/infra.md,docs/tests.md) updated to match — README's old "Authentication: Not included" claim was stale now that it's available as opt-in.
Bug found and fixed via test-first development: the rate limiter was fully bypassed whenever auth was disabled, because the auth middleware's early-return also skipped the independent rate-limit check. Fixed, with a regression test.
Tests: 550 passing (32 new), ruff clean.