mirror of
https://github.com/zitadel/zitadel.git
synced 2026-08-19 01:14:48 -05:00
# Which Problems Are Solved 1. SSL/TLS handshake failures on Cloud Run (middleware self-loopback) PR #11903 changed the middleware (proxy.ts) to fetch security settings via fetch(origin + "/security") on every request, including non-proxy routes like /login. On Cloud Run, this self-loopback goes through the Google Front End (GFE) load balancer, causing intermittent SSL routines::record layer failure errors that were tenant-consistent. 2. The ClassifiedConnectError introduced in #11926 set this.name = "ClassifiedConnectError", which broke ConnectError's custom Symbol.hasInstance duck-typing check (v.name === "ConnectError"). This caused ConnectError.from() inside the connectRPC transport's abort handler to re-wrap classified errors as new ConnectError instances with Code.Unknown — losing the original gRPC error code and all classification metadata. # How the Problems Are Solved Middleware: eliminate self-loopback fetch: - Replaced the fetch(origin + "/security") self-loopback with a direct fetch to ZITADEL_API_URL using the Connect protocol (POST + JSON), bypassing the load balancer entirely - Security settings are cached in-memory with a 1-hour TTL per instance host - Extracted the fetching/caching logic into src/lib/server/security-settings.ts Removed the now-unused /security API route (src/app/security/route.ts) - CSP headers with iframe origins are now applied to all routes without any loopback Error classification interceptor: fixed - Keep this.name = "ConnectError" in ClassifiedConnectError so the duck-typing Symbol.hasInstance check passes - The branded Symbol.for check via isClassifiedError() still correctly distinguishes the subclass - Remove redundant Object.setPrototypeOf call (the super constructor already handles it via new.target) - Replace remaining instanceof ConnectError checks with isClassifiedError() in setUserPassword and checkSessionAndSetPassword