Skip to content

test: guard the crudauth follow-up behaviors - #300

Open
emiliano-go wants to merge 2 commits into
benavlabs:mainfrom
emiliano-go:test/crudauth-followup-regression
Open

emiliano-go wants to merge 2 commits into
benavlabs:mainfrom
emiliano-go:test/crudauth-followup-regression

Conversation

@emiliano-go

@emiliano-go emiliano-go commented Sep 19, 2026

Copy link
Copy Markdown
Collaborator

Adds regression coverage for the wiring and fixes landed in #292, plus the earlier auth, admin, CORS, docs, data-layer and error-handling changes.

What is covered:

  • RATE_LIMITER_BACKEND and SESSION_BACKEND are selected independently, so the limiter no longer follows the session backend.
  • The per-path tier limit is read through the request's own database dependency (dependency overrides honored) instead of opening a session directly, which was sending the lookup to the configured database.
  • Each shared Redis client in infrastructure/redis.py is built from its own settings, and the same clients are injected into crudauth and the cache backend.
  • The signup schema and crudauth share one password policy object, built from the PASSWORD_* settings, so the documented rules cannot drift from the enforced ones. A password missing several classes reports all of them.
  • The admin user form hashes passwords off the event loop and enforces the policy.
  • /login finishes through the session transport's complete_login, forwarding remember_me and the login metadata.
  • The mounted /api/v1/auth/* and OAuth URLs are unchanged. Only a fully configured Google is wired, and an absolute same-origin redirect_to is refused like any other absolute target.
  • The session transport receives the configured CSRF, session count, timeout and cleanup settings, IPv6 callers are rate limited by their /64, and crudauth is initialized on startup.
  • Gated docs are served from the configured DOCS_URL, REDOC_URL and OPENAPI_URL.
  • The default CORS origins are explicit local origins, never a wildcard, and the origin list parsing strips whitespace and empties.
  • The metadata uses the standard constraint naming convention, and the api_keys tables declare no duplicated single-column indexes.
  • API key 404 and 403 responses use the generic global-handler bodies with a support id.

Verification:

  • Each test was checked against a mutation that reintroduces the specific regression, and fails as expected.
  • ruff and mypy are clean.
  • Full backend suite: 345 passing.

Add regression coverage for the composition-root wiring and the fixes from the migration: rate limiter and session backends chosen independently; the tier limit read through the request's own database dependency; each shared Redis client built from its own settings and reused by crudauth and the cache; one password policy shared by the signup schema and crudauth; admin passwords hashed and policy-checked off the event loop; logins finished through the session transport's complete_login; and the mounted auth URLs unchanged.

Every test was checked against a mutated implementation to confirm it fails when the behavior regresses. Full suite: 324 passing; ruff and mypy clean.
@emiliano-go

Copy link
Copy Markdown
Collaborator Author

One thing I deliberately left out, to keep the suite dependency-free: an automated check of the limiter against a real Redis.

The single-process run against Postgres and Redis already confirmed that per-path counters land in Redis under the expected keys, but no test exercises the RedisBackend increments, because the suite runs the limiter in memory. The current coverage only reaches the Redis branch through construction (client identity).

If you want CI to require a Redis service, I can add a small test marked slow and redis, skipped unless a Redis URL is configured, that starts the app against real Redis, spends a per-path budget, and asserts the counter key exists in RATE_LIMITER_REDIS_DB with the expected window TTL. Otherwise the suite stays self-contained as it is now.

@emiliano-go

Copy link
Copy Markdown
Collaborator Author

300th PR btw 🥳!

Cover the composition root, OAuth and session wiring, password policy, the auth URL contract, gated docs, CORS defaults, constraint naming, api_keys index hygiene, and generic route errors:

- OAuth provider selection, new-user name bounds, session transport settings, IPv6 rate-limit keys, and the rate-limit fallbacks;
- password policy drift, admin hashing and policy checks, login through the session transport, and the auth URL contract;
- gated docs served from the configured URLs, and crudauth initialization on startup;
- explicit CORS defaults, the standard metadata naming convention, and no duplicated single-column indexes;
- generic API key 404 and 403 bodies, and absolute same-origin OAuth redirects refused.

Each test was checked against a mutated implementation. Full suite: 345 passing; ruff and mypy clean.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant