Commit Graph

10 Commits

Author SHA1 Message Date
Barcode Betty 7b595744e1 fix(api): mypy no-redef and no-any-return errors on dev (CAR-1335)
CI / lint (pull_request) Successful in 5s
CI / typecheck (pull_request) Successful in 18s
CI / test (pull_request) Successful in 22s
CI / build-and-push (pull_request) Has been skipped
The api typecheck job is continue-on-error but still posts a failure
status that blocks merges. Three pre-existing mypy errors on dev were
inherited by every PR based on it:

1. middleware/rate_limit.py: duplicate 'name already defined' for
   _public_limiter, _auth_limiter, _auth_strict_limiter (declared at
   lines 111-113 and again at 124-126). The second set is redundant
   because actual assignment happens inside the if/else below.
2. cache.py:43 - 'Returning Any' from .get(); the redis client's get()
   return type isn't narrowed to bytes|str, so the final 'return value'
   branch is Any. Wrap with str() to satisfy the declared str|None.
3. middleware/rate_limit.py:150 - 'Returning Any' from _get_client_ip.
   request.headers.get() and request.client.host are typed Any; wrap
   the branches with str() to match the declared str return.

Refs CAR-1335.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-06-09 05:25:41 +00:00
Savannah Savings 3860a5d061 Merge pull request 'Fix CAR-1132: SQLite UUID binding and User.id defaults in test fixtures' (#42) from betty/car-1132-comprehensive-fix into dev
CI / lint (push) Failing after 7s
CI / typecheck (pull_request) Failing after 18s
CI / test (pull_request) Successful in 22s
CI / build-and-push (pull_request) Has been skipped
CI / build-and-push (push) Has been skipped
CI / typecheck (push) Failing after 17s
CI / lint (pull_request) Failing after 3s
CI / test (push) Successful in 22s
2026-06-09 01:01:09 +00:00
Barcode Betty c243014cd1 CAR-1283 rebase onto dev: update src/cartsnitch_api/middleware/rate_limit.py
CI / lint (pull_request) Has been cancelled
CI / typecheck (pull_request) Has been cancelled
CI / test (pull_request) Has been cancelled
CI / build-and-push (pull_request) Has been cancelled
2026-06-06 00:39:19 +00:00
Barcode Betty 2b20946ad7 fix: /health returns 503 on DB failure, pool_timeout=30, CI typecheck fixes
CI / lint (pull_request) Failing after 4s
CI / typecheck (pull_request) Failing after 25s
CI / test (pull_request) Failing after 1m5s
CI / build-and-push (pull_request) Has been skipped
QA review of PR #39 (CAR-1121) identified three blocking issues; this
commit addresses all three plus the typecheck errors flagged as CI RED.

CAR-1077 (PR #39) changes:
- database.py: add pool_timeout=30 so the engine fails fast when the
  connection pool is exhausted (defends against the "server closed
  connection unexpectedly" pod failures).
- routes/health.py: /health now calls SELECT 1 through Depends(get_db)
  and raises HTTPException(503) when the database is unreachable, so
  Kubernetes readiness probes can correctly mark the pod unhealthy and
  stop routing traffic to it.  Logs the failure at exception level for
  observability.
- Drop .mcp.json from this PR (root-level MCP server config, not
  related to the pool fix; tracked separately).

CI typecheck fixes (pre-existing on dev, were failing mypy on PR #39):
- auth/passwords.py: cast bcrypt return values so mypy doesn't widen
  to Any.
- config.py: silence the false-positive call-arg on Settings() — the
  three required fields are populated from the environment by
  pydantic-settings at runtime.
- cache.py: coerce the bytes/str union returned by the redis client
  to the documented str | None return type.
- middleware/rate_limit.py: annotate the three module-level limiters
  with the RateLimitBackend protocol, cast the redis zrange score to
  float before arithmetic, and add max_requests/window_seconds to the
  protocol so the response-header builder can read them.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-06-02 14:53:16 +00:00
Barcode Betty 83ee3e814b Cast oldest[0][1] to float in RedisSlidingWindow fallback
CI / lint (pull_request) Successful in 5s
CI / typecheck (pull_request) Successful in 27s
CI / test (pull_request) Successful in 35s
CI / build-and-push (pull_request) Failing after 7s
mypy complained: 'Unsupported operand types for - ("str" and "float")'
on rate_limit.py:87. redis-py's zrange withscores=True returns the
score as whatever the codec produces (often str), but we treat it as
a numeric millisecond timestamp. Cast to float before subtracting
the cutoff.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 13:48:26 +00:00
Barcode Betty b4ad140796 Fix mypy typecheck errors and FK format mismatch in test fixtures
CI / lint (pull_request) Successful in 4s
CI / typecheck (pull_request) Successful in 30s
CI / test (pull_request) Failing after 39s
CI / build-and-push (pull_request) Has been skipped
Three categories of pre-existing CI failure on PR #42:

1. typecheck (mypy src/cartsnitch_api, 9 errors):
   - src/cartsnitch_api/config.py:89 — Settings() needs required secret
     args that only exist in env at runtime; suppress with
     type: ignore[call-arg]
   - src/cartsnitch_api/cache.py:38 — redis-py returns Any/bytes,
     normalize to str before returning from get()
   - src/cartsnitch_api/middleware/rate_limit.py:128,131,134 — three
     limiter globals were inferred as RedisSlidingWindow on the if
     branch then re-assigned InMemorySlidingWindow on else; declare
     them as RateLimitBackend up front
   - src/cartsnitch_api/middleware/rate_limit.py:181,187 —
     RateLimitBackend Protocol didn't declare max_requests even
     though both InMemorySlidingWindow and RedisSlidingWindow expose
     it; add max_requests: int to the Protocol

2. test (FK constraint on purchases.user_id):
   - tests/conftest.py:_create_test_user_and_session stored user_id
     as 32-char hex; test_e2e conftest reads it via raw SQL and wraps
     in uuid.UUID (36 chars) before passing to Purchase.user_id, so
     the FK never matched. Switch back to str(uuid.uuid4()) (36 chars)
     so the stored value and the FK bind value use the same format.

3. Verify lint + format clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 12:57:54 +00:00
Barcode Betty 8a4c194e39 feat: Redis-backed rate limiting with stricter auth limits
- Add rate_limit_auth_requests (5/min) and rate_limit_auth_window_seconds (60) settings
- Add rate_limit_redis_enabled flag for opt-in Redis usage
- Refactor _SlidingWindowCounter into InMemorySlidingWindow class
- Add RedisSlidingWindow using sorted sets with fallback to in-memory
- Add third _auth_strict_limiter for POST /auth/* paths (5 req/min)
- Add protocol-based backend selection at module load time
- Update tests for auth strict limiter and Redis fallback behavior

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-15 02:10:02 +00:00
Paperclip 26f3415eab feat: Redis-backed rate limiting with stricter auth limits
- Add rate_limit_auth_requests (5/min) and rate_limit_auth_window_seconds (60)
  settings to config.py
- Refactor rate_limit.py to use protocol/ABC pattern with InMemorySlidingWindow
  and RedisSlidingWindow implementations
- Add RedisSlidingWindow using sorted sets for distributed rate limiting
- Add auth_strict_limiter for /auth/* POST endpoints (5 req/min per IP)
- Fall back to in-memory when Redis is unavailable
- Update tests to cover new functionality

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-14 15:46:52 +00:00
CartSnitch Engineer Bot b5df9aba1e fix(security): use SHA-256 hash for rate limit key instead of token suffix
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-14 11:36:17 +00:00
Coupon Carl b7e6f637a7 feat: merge cartsnitch/api into api/ subdirectory
Consolidate API gateway service into monorepo.
Squashed from https://github.com/cartsnitch/api main (89bacb1).

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-03-28 02:24:02 +00:00