refactor: security and rate limit metrics come from spans, and SecurityMetrics and RateLimitMetrics are gone
Summary
Part of #389, the security and rate limit area. The 15 instruments in SecurityMetrics and RateLimitMetrics now come from spans, and every label survives as a span attribute, as decided for #389 (keep the labels instead of switching to HTTP route metrics).
Changes
AuthService.login runs in an auth.login span with method and success. Token and CSRF rejections, admin route checks, lockouts, logins on locked accounts, weak passwords and admin password resets each leave an auth.* span where the metric used to be recorded. RateLimitService leaves a rate_limit.request span per check and a rate_limit.decision span when a rule applies. The bypass counter comes from requests whose algorithm is bypassed. The collector's signaltometrics connector makes the same 15 series, and the two dashboards use the new label names (auth_reason, rate_limit_endpoint, ...). The services take trace.Tracer.
Type of Change
- Bug fix (non-breaking change that fixes an issue)
- New feature (non-breaking change that adds functionality)
- Breaking change (fix or feature that would cause existing functionality to change)
- Documentation update
- Refactoring (no functional changes)
- CI/CD or tooling changes
Test Plan
- Backend unit tests pass (
cd backend && uv run pytest tests/unit) - Frontend unit tests pass (
cd frontend && npm run test) - Backend E2E tests pass (
docker compose exec -T backend sh -c 'uv sync --group test --no-dev --frozen --no-install-project --no-build && pytest tests/e2e') - Frontend E2E tests pass (
cd frontend && npm run test:e2e) - API spec and client regenerated if routes or schemas changed (
./deploy.sh openapi, then./deploy.sh types), never edited by hand - Manual testing performed
Validation: unit 570 passed, contract 3 passed, e2e 488 passed and 1 skipped. Driving the services from the API container (a bad token, a failed and a good login, a too-short password, five rate limit checks) gave exactly those counts at the collector.
Checklist
- My code follows the project's style guidelines
- I have run
pre-commit run --all-filesand all checks pass - I have added tests that prove my fix/feature works
- I have updated documentation if needed
- My changes don't introduce new warnings
Summary by cubic
Replaces the SecurityMetrics and RateLimitMetrics instrument classes with spans, so all 15 security and rate limit metrics are now derived from traces.
- Logins, token and CSRF rejections, admin checks, lockouts, weak passwords, and password resets each leave an
auth.*span; rate limit checks leaverate_limit.requestandrate_limit.decisionspans. - The collector's
signaltometricsconnector produces the same series, and every label survives as a span attribute. - Services now take a
trace.Tracerinstead of the metric classes; the dashboards and metrics reference use the new label names (auth_reason,rate_limit_endpoint, ...); the bypass counter now comes from requests whose algorithm isbypassed.