Compare commits

...

10 Commits

Author SHA1 Message Date
Barcode Betty 135064fc10 Merge pull request 'fix(ci): resolve dev lint + typecheck failures (CAR-1330)' (#48) from betty/car-1330-dev-ci-fix into dev
CI / lint (push) Successful in 7s
CI / typecheck (push) Successful in 18s
CI / test (push) Successful in 22s
CI / build-and-push (push) Successful in 1m6s
2026-06-11 04:17:51 +00:00
Savannah Savings b141377b02 Merge pull request 'fix(api): document dispose_engine lazy import + regression test (CAR-1135)' (#45) from barcode-betty/fix-car-1135-dispose-engine into dev
CI / lint (push) Successful in 4s
CI / typecheck (push) Successful in 19s
CI / test (push) Successful in 23s
CI / build-and-push (push) Successful in 1m30s
2026-06-10 05:13:18 +00:00
Barcode Betty a3a01eefe2 Merge pull request 'fix(ci): simplify Push step to match auth pattern (CAR-1362)' (#53) from betty/car-1362-push-unknown-fix into dev
CI / lint (push) Successful in 4s
CI / typecheck (push) Successful in 18s
CI / test (push) Successful in 24s
CI / build-and-push (push) Successful in 1m45s
2026-06-10 04:10:58 +00:00
Barcode Betty 354e26295c fix(ci): simplify Push step to match auth pattern (CAR-1362)
CI / lint (pull_request) Successful in 5s
CI / typecheck (pull_request) Successful in 20s
CI / test (pull_request) Successful in 22s
CI / build-and-push (pull_request) Has been skipped
The Push Docker image step is failing post-merge of CAR-1362 with
buildx "unknown" error after layers push successfully. The pre-existing
failure was masked by the cache export error.

Simplify the Push step to match the proven-green cartsnitch/auth/ci.yml
pattern: drop `file: ./Dockerfile` (default) and `build-args:`
(APT_CACHE_BUST is only used to bust apt cache in stage 1 of multi-
stage build, not needed for the rebuilt image). Keep `if: github.event_name
== "push"` to skip on pull_request events.

Diff: 4 lines removed from .gitea/workflows/ci.yml Push step.

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-06-10 04:08:53 +00:00
Barcode Betty 30a447674d Merge pull request 'fix(ci): remove GHA cache-from/cache-to (CAR-1357)' (#52) from betty/car-1362-remove-gha-cache-dev into dev
CI / lint (push) Successful in 6s
CI / typecheck (push) Successful in 18s
CI / test (push) Successful in 21s
CI / build-and-push (push) Failing after 1m8s
2026-06-09 18:03:04 +00:00
Barcode Betty 7a7d8f451e fix(ci): remove GHA cache-from/cache-to (CAR-1357)
CI / lint (pull_request) Successful in 9s
CI / typecheck (pull_request) Successful in 18s
CI / test (pull_request) Successful in 23s
CI / build-and-push (pull_request) Has been skipped
The build-and-push job fails post-merge of CAR-1356 REGISTRY_TOKEN fix:
cache-from/cache-to: type=gha backend does not exist on Gitea. Build
succeeds but post-build cache export fails and cascades to skipping the
Push Docker image step. Confirmed in uat run 3444 + dev run 3445.

Per CAR-1362, drop cache-from and cache-to from both Build and Push
Docker image steps. Matches proven-green cartsnitch/auth/ci.yml pattern.

Refs: CAR-1362, CAR-1356, CAR-1330, CAR-1357.

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-06-09 18:01:21 +00:00
Barcode Betty 79e8baa609 fix(ci): use REGISTRY_TOKEN for build-and-push registry login (CAR-1330)
CI / lint (push) Successful in 4s
CI / typecheck (push) Successful in 17s
CI / test (push) Successful in 25s
CI / build-and-push (push) Failing after 54s
Squashed fix swaps github.token → secrets.REGISTRY_TOKEN at .gitea/workflows/ci.yml:121, matching the proven-green cartsnitch/auth pattern (CAR-1009). Parity fix with uat PR #49 to prevent reintroduction on next dev→uat promotion.

Note: includes 3 absorbed lint/typecheck commits from PR #48 (already merged to dev via #48) to unblock CI on this branch. No app code changes; one-line CI config swap only.

QA: PR #50 approved by @cs_charlie (review id 4616); CI run 3443 lint/typecheck/test all green.
Co-authored-by: Barcode Betty <32+cs_betty@noreply.git.farh.net>
Co-committed-by: Barcode Betty <32+cs_betty@noreply.git.farh.net>
2026-06-09 17:47:11 +00:00
Barcode Betty 8deaf6e599 fix(ci): resolve dev lint + typecheck failures (CAR-1330)
CI / lint (pull_request) Successful in 5s
CI / typecheck (pull_request) Successful in 19s
CI / test (pull_request) Successful in 22s
CI / build-and-push (pull_request) Has been skipped
Three CI-blocking issues on dev branch (also present on uat, fixed in 2b20946):

1. tests/conftest.py — remove extra blank line (ruff format).
2. src/cartsnitch_api/middleware/rate_limit.py — delete duplicate
   _public_limiter/_auth_limiter/_auth_strict_limiter forward-decl block
   (the second occurrence; mypy no-redef).
3. src/cartsnitch_api/cache.py:38 — annotate
   value: str | bytes | None so mypy doesn't widen redis client return
   to Any (no-any-return).

Verified: ruff check . && ruff format --check . && mypy src/cartsnitch_api
all pass.

Sibling of CAR-1330 (which fixes uat directly). Heals dev so future
dev → uat promotions stay green.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-06-09 11:13:44 +00:00
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
Barcode Betty 4877513bbf style: ruff format conformance (CAR-1335)
- tests/test_openapi.py: collapse 2 blank lines to 1 (ruff format)
- tests/conftest.py: collapse 2 blank lines to 1 (ruff format)

These format nits block lint (a hard gate). The conftest.py one was
introduced in CAR-1132 (#42) and would have blocked every subsequent PR
on dev until fixed.

Refs CAR-1335, CAR-1135.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-06-09 05:23:36 +00:00
5 changed files with 6 additions and 16 deletions
+1 -7
View File
@@ -118,7 +118,7 @@ jobs:
echo "CalVer tag: $VERSION"
- name: Log in to Gitea Container Registry
run: echo "${{ github.token }}" | docker login git.farh.net -u ${{ github.actor }} --password-stdin
run: echo "${{ secrets.REGISTRY_TOKEN }}" | docker login git.farh.net -u ${{ github.actor }} --password-stdin
- name: Extract metadata
id: meta
@@ -140,8 +140,6 @@ jobs:
labels: ${{ steps.meta.outputs.labels }}
build-args: |
APT_CACHE_BUST=${{ github.run_id }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Scan api image for vulnerabilities
uses: anchore/scan-action@v5
@@ -162,13 +160,9 @@ jobs:
uses: docker/build-push-action@v6
with:
context: .
file: ./Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
APT_CACHE_BUST=${{ github.run_id }}
cache-from: type=gha
- name: Create git tag
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
+2 -2
View File
@@ -35,12 +35,12 @@ class CacheClient:
async def get(self, key: str) -> str | None:
if not self._client:
return None
value = await self._client.get(key)
value: str | bytes | None = await self._client.get(key)
if value is None:
return None
if isinstance(value, bytes):
return value.decode("utf-8", errors="replace")
return value
return str(value)
async def set(self, key: str, value: str, ttl_seconds: int = 300) -> None:
if not self._client:
+2 -6
View File
@@ -121,10 +121,6 @@ if settings.rate_limit_redis_enabled:
logger.warning("Failed to connect to Redis for rate limiting, using in-memory: %s", e)
_use_redis = False
_public_limiter: RateLimitBackend
_auth_limiter: RateLimitBackend
_auth_strict_limiter: RateLimitBackend
if _use_redis and _redis_client:
_public_limiter = RedisSlidingWindow(
_redis_client, settings.rate_limit_requests, settings.rate_limit_window_seconds
@@ -151,8 +147,8 @@ def _get_client_ip(request: Request) -> str:
"""Extract client IP, respecting X-Forwarded-For behind a reverse proxy."""
forwarded = request.headers.get("x-forwarded-for")
if forwarded:
return forwarded.split(",")[0].strip()
return request.client.host if request.client else "unknown"
return str(forwarded.split(",")[0].strip())
return str(request.client.host) if request.client else "unknown"
def _get_rate_limit_key(request: Request) -> tuple[str, RateLimitBackend]:
-1
View File
@@ -117,7 +117,6 @@ def _register_event_listeners():
event.listen(cls, "before_insert", _set_timestamp_defaults)
TEST_JWT_SECRET = secrets.token_urlsafe(32)
TEST_SERVICE_KEY = secrets.token_urlsafe(32)
TEST_FERNET_KEY = "7reF42nmTwbdN21PBoubGp7h_FU8qSimstmlaMLoRK8="
+1
View File
@@ -18,6 +18,7 @@ def test_dispose_engine_importable_from_database():
assert callable(dispose_engine)
assert dispose_engine.__name__ == "dispose_engine"
EXPECTED_ROUTES = [
# Auth (3 — register/login/refresh are handled by Better-Auth service)
("get", "/auth/me"),