fix(GRO-2652): promote boot ECONNRESET resilience to UAT (dev→uat) #223

Merged
Flea Flicker merged 18 commits from dev into uat 2026-08-05 10:22:03 +00:00

18 Commits

Author SHA1 Message Date
Flea Flicker f1b0a53520 test(GRO-2652): stub fetch in auth tests to fix OIDC discovery timeout flake
CI / Lint & Typecheck (push) Successful in 19s
CI / Test (push) Successful in 22s
CI / Lint & Typecheck (pull_request) Successful in 19s
CI / Test (pull_request) Successful in 20s
CI / Build & Push Docker Images (pull_request) Successful in 52s
CI / Build & Push Docker Images (push) Successful in 1m45s
AbortSignal.timeout(5000) in initAuth's discovery fetch races with
vitest's 5000ms default test timeout, causing intermittent failures on CI push
runs. Stub fetch to return ok:false instantly so tests complete in <1s.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-08-05 10:04:31 +00:00
Flea Flicker f32e9a6889 fix(GRO-2652): reset authInitPromise on failure so retry loop actually retries
CI / Lint & Typecheck (push) Successful in 20s
CI / Test (push) Failing after 21s
CI / Build & Push Docker Images (push) Has been skipped
CI / Lint & Typecheck (pull_request) Successful in 18s
CI / Test (pull_request) Failing after 25s
CI / Build & Push Docker Images (pull_request) Has been skipped
Merging Phase 1 fix — CI all green (lint, test, build all success). Resolves QA's retry-memoization concern from PR #223 review.
2026-08-05 10:00:12 +00:00
Flea Flicker a1b27b5501 fix(GRO-2652): reset authInitPromise on failure so retry loop actually retries
CI / Lint & Typecheck (pull_request) Successful in 19s
CI / Test (pull_request) Successful in 21s
CI / Build & Push Docker Images (pull_request) Successful in 53s
Previously the initAuth() function set authInitPromise to the async IIFE's
Promise but never cleared it on rejection. The index.ts retry loop called
initAuth() up to 10 times, but on attempt 2+ the check
`if (authInitPromise) { await authInitPromise; return; }` would immediately
re-throw the original rejection without performing a real retry.

Fix: wrap the final `await authInitPromise` in try/catch and reset
authInitPromise = null on error. This allows the index.ts retry loop to
create a fresh attempt on each call after a failure.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-08-05 09:52:31 +00:00
Flea Flicker ae0ce3824f fix(GRO-2652): reset authInitPromise on failure so retry loop actually retries
CI / Lint & Typecheck (pull_request) Failing after 10s
CI / Test (pull_request) Failing after 24s
CI / Build & Push Docker Images (pull_request) Has been skipped
Previously the initAuth() function set authInitPromise to the async IIFE's
Promise but never cleared it on rejection. The index.ts retry loop called
initAuth() up to 10 times, but on attempt 2+ the check
`if (authInitPromise) { await authInitPromise; return; }` would immediately
re-throw the original rejection without performing a real retry.

Fix: wrap the final `await authInitPromise` in try/catch and reset
authInitPromise = null on error. This allows the index.ts retry loop to
create a fresh attempt on each call after a failure.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-08-05 09:44:12 +00:00
Flea Flicker f98c5ccaf7 fix(GRO-2652): restore ci.yml from double-base64 corruption + UAT_PLAYBOOK §4.20 clients-from-auth
CI / Lint & Typecheck (push) Successful in 21s
CI / Test (pull_request) Successful in 21s
CI / Lint & Typecheck (pull_request) Successful in 34s
CI / Test (push) Failing after 40s
CI / Build & Push Docker Images (push) Has been skipped
CI / Build & Push Docker Images (pull_request) Successful in 27s
2026-08-05 09:29:16 +00:00
Flea Flicker 61f23e47f1 docs(GRO-2359): add UAT_PLAYBOOK §4.20 clients-from-auth test cases
CI / Lint & Typecheck (pull_request) Successful in 19s
CI / Test (pull_request) Successful in 21s
CI / Build & Push Docker Images (pull_request) Successful in 1m9s
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-08-05 09:20:03 +00:00
Flea Flicker ab5f08e4c0 fix(GRO-2652): restore ci.yml from double-base64 corruption; fix outpuds typo
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-08-05 09:19:55 +00:00
gb_flea 5accf73363 ci: trigger CI for dev branch (PR-223 dev→uat) 2026-08-05 09:04:17 +00:00
Flea Flicker 299a157561 fix(GRO-2652): boot ECONNRESET resilience — retry-with-backoff in initAuth, server-first startup
Merges feature/GRO-2652-boot-econnreset-resilience into dev. CI passed (run #440). Fixes PROD CrashLoopBackOff caused by bare top-level await initAuth() + unhandled ECONNRESET in auth_provider_config DB query.
2026-08-05 09:01:12 +00:00
gb_flea af1af5c211 ci: trigger CI run for ignore-error=true cache-to fix 2026-08-05 08:56:30 +00:00
Flea Flicker 713e8bf415 ci: add ignore-error=true to all cache-to targets
Gitea OCI registry sporadically rejects cache blob writes with
"error writing layer blob: unknown" — this fails the build step
even though the image itself was pushed successfully. Adding
ignore-error=true makes cache write failures non-fatal so the
build proceeds regardless of registry-side cache issues.

Fixes recurring CI failure on Build and push Seed image step.
2026-08-05 08:54:00 +00:00
Flea Flicker 8d42bfffc9 test(GRO-2652): add boot resilience UAT test cases (TC-API-19.x)
CI / Test (pull_request) Successful in 25s
CI / Lint & Typecheck (pull_request) Successful in 28s
CI / Build & Push Docker Images (pull_request) Successful in 56s
New section 4.19 verifies:
- /health available before initAuth completes
- auth routes return 503 (not crash) during init retry window
- pod restart count stays stable after deploy
- retry log lines emitted correctly
- auth recovers after transient DB hiccup

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-08-05 08:22:00 +00:00
Flea Flicker 095efb1cca fix(GRO-2652): start server before initAuth; retry auth init on ECONNRESET
Previously: await initAuth() was a top-level ESM await. Any boot-time
ECONNRESET from Postgres propagated as an uncaught module-evaluation
error and killed the process before the server even started.

Now:
- serve() starts immediately so /health and public routes are available
- initAuth() runs in a retry loop (up to 10 attempts, exponential
  500 ms → 30 s); a permanent failure degrades to 503 on auth routes
  (existing catch-to-503 in authRouter) rather than crashing the pod

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-08-05 08:21:14 +00:00
Flea Flicker 632dadd064 fix(GRO-2652): retry DB query in initAuth on transient ECONNRESET
The auth_provider_config DB query at boot has no error handling;
a transient ECONNRESET causes authInitPromise to reject, propagating
to the top-level await initAuth() and crashing the process (exit 1).

Add up to 5 retry attempts with exponential backoff (1 s, 2 s, 4 s, 8 s)
so a single connection reset does not abort initialization.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-08-05 08:17:31 +00:00
Flea Flicker dace2c4e66 fix(GRO-2586): enforce trusted-origins allowlist on Better Auth CORS responses (#219)
CI / Lint & Typecheck (push) Successful in 19s
CI / Test (push) Successful in 21s
CI / Build & Push Docker Images (push) Successful in 1m4s
fix(GRO-2586): enforce trusted-origins allowlist on Better Auth CORS responses

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-06-26 13:35:59 +00:00
Flea Flicker c01e4acf0a feat(GRO-2425): split CORS_ORIGIN on commas for multiple trusted auth origins (#216)
CI / Test (push) Successful in 30s
CI / Lint & Typecheck (push) Successful in 45s
CI / Build & Push Docker Images (push) Successful in 1m10s
CI / Test (pull_request) Successful in 25s
CI / Lint & Typecheck (pull_request) Failing after 12m18s
CI / Build & Push Docker Images (pull_request) Has been skipped
feat(GRO-2425): split CORS_ORIGIN on commas for multiple trusted auth origins

Co-authored-by: Flea Flicker <flea@groombook.dev>
Co-committed-by: Flea Flicker <flea@groombook.dev>
2026-06-18 00:46:29 +00:00
Flea Flicker 10b78d810d Merge pull request 'feat(GRO-2359): add POST /api/portal/clients-from-auth for OOBE' (#212) from feature/2357-p2-portal-clients-from-auth into dev
CI / Test (push) Successful in 26s
CI / Lint & Typecheck (push) Successful in 32s
CI / Build & Push Docker Images (push) Successful in 41s
GRO-2359 (api): feat(GRO-2359): add POST /api/portal/clients-from-auth for OOBE (#212)
2026-06-11 16:34:34 +00:00
Flea Flicker cdeebec021 feat(GRO-2359): add POST /api/portal/clients-from-auth for OOBE (web)
CI / Test (pull_request) Successful in 29s
CI / Lint & Typecheck (pull_request) Successful in 41s
CI / Build & Push Docker Images (pull_request) Successful in 1m40s
The OOBE flow on the web portal calls this endpoint to create a fresh
`clients` row bound to the Better Auth user's email when the SSO
bridge returns 404. Returns 201 on success, 409 if a client with that
email already exists (portal-selection case), 401/503 on auth issues,
400 on invalid body.

The OOBE success path navigates the user back to `/` and lets the
existing `session-from-auth` re-bridge; the new client is now
resolvable by email, so the bridge mints a real portal session.

Tests cover: 401 (no session), 400 (zod), 201 + persisted values
(name trimmed, optional fields normalized to null), 409 (existing
client or unique-constraint race), 503 (auth not configured).

Paired with the web PR on `feature/2357-p2-sso-to-oobe-routing`.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-06-11 16:17:16 +00:00