chore: back-merge 4.15.3 hotfix into master#3408
Conversation
The exception scope check introduced in #3323 requires exceptions.uniqueId to equal server.uniqueID, but the server-signed validation path returns before getUniqueId() ever runs and /api/info does not include a uniqueId field, so the local uniqueID is missing on that path and uniqueId-scoped exceptions were always disqualified. Resolve the workspace uniqueID from the server before validating when the payload carries a uniqueId-scoped exceptions block, persist it via WEBVIEW_SERVER_UNIQUE_ID_UPDATED so subsequent runs (including offline cache validation) keep working, and keep rejecting when the fetched value does not match. Also compare exceptions.domain case-insensitively (DNS names are case-insensitive per RFC 4343).
Audited the supported-versions subsystem end to end after the
uniqueId-scope escalation and fixed the confirmed defects:
- Wrap the cache/builtin fallback validation in a helper with try/catch
so a malformed cached payload can no longer reject the update before
the error state is dispatched, which left fetchState stuck at
'loading' and suppressed the UnsupportedServer block gate.
- Catch rejections at all four fire-and-forget validation call sites.
- Fall back to the persisted workspace uniqueID when the fresh fetch
fails so the cloud lookup is not skipped for previously-known servers.
- Switch uniqueID/version/gitCommitHash reducer cases from upsert to
update so a late identity dispatch cannot resurrect a server deleted
while a validation was in flight.
- Guard getExpirationMessageTranslated against payloads whose i18n
dictionary lacks both the user language and 'en'; the missing guard
crashed the async check and silently suppressed the expiring-
workspace warning dialog.
- Revalidate all servers on powerMonitor 'resume' (the window 'online'
event does not fire when waking with the same network connected).
- Use the real currentView state in SupportedVersionDialog's effect
dependencies; the previous dependency was the imported reducer
function, which never changes, so the dialog never re-checked on
view switches.
- Add a 'Check again' button to the unsupported-workspace screen so
users can re-trigger validation without restarting the app.
- Fix logRequestError printing a literal ${description}.
Also relax the exception scope check for UNKNOWN local identity: an
unfetchable workspace uniqueID (e.g. settings.public restricted by
enterprise API ACLs) no longer disqualifies a domain-matched exception;
a PROVEN uniqueID mismatch still rejects. The gate is client-side UX
enforcement rather than a security boundary, and wrongly blocking a
legitimate workspace is the worse failure mode.
Server, cloud, and cache supported-versions payloads are fetched from or for the server being validated, so their exceptions block cannot belong to another tenant. For these sources a domain/uniqueId scope mismatch is now logged as a diagnostic warning instead of disqualifying the exception. The bundled builtin payload is the only source that could carry another deployment's exceptions and keeps the strict scope requirement. This removes the remaining paths where a valid, unexpired exception could be rejected over unverifiable or drifted identity data (restricted settings.public API, rotated workspace uniqueID, stale persisted state).
A missing or unparseable enforcementStartDate previously produced an Invalid Date that failed the future-date comparison and fell through to the unsupported verdict — blocking the workspace based on incomplete payload data. Blocking now requires a valid, past enforcement date: uncertain data keeps the server usable until a payload with a valid enforcement date proves enforcement is active.
…nfo contract; try both fallback sources The desktop's ServerInfo type declared fields the server never returns to unauthenticated callers (verified against the server source, apps/meteor/server/api/lib/getServerInfo.ts): - Remove the fictional uniqueId field. No server version includes it in /api/info; the workspace uniqueID comes from settings.public and is resolved on demand by withExceptionScopeUniqueId. Remove the dead serverInfoResult.uniqueId fallback in updateSupportedVersionsData. - Mark build, marketplaceApiVersion, and commit optional and document that they only appear for authenticated view-statistics callers; the desktop always calls /api/info unauthenticated. The sha-exception path uses the persisted server.gitCommitHash pushed by the injected script instead. - Rebuild the default test fixture to mirror the real unauthenticated wire shape (trimmed major.minor version, no uniqueId/commit/info) so the suite can no longer validate assumptions against fields real servers do not send — the gap that let the exception-scope defect pass CI. Switch beforeEach to jest.resetAllMocks(), fixing latent cross-test mock leakage the honest fixtures surfaced. Also rework the offline fallback to try BOTH remaining sources instead of picking one by timestamp: the bundled builtin payload never carries tenant exceptions, so preferring a fresher builtin over a cache that holds the tenant's exception blocked a workspace that should stay usable. Candidates are checked in freshness order and the first source that supports the server wins; blocking requires every available source to fail. This keeps the stale-cache rescue from #3388 while never losing a cached exception to it.
Asserts the unauthenticated /api/info response shape against a real server (open.rocket.chat): trimmed major.minor version, no uniqueId, no commit/info blocks, string minimumClientVersions, JWT-shaped supportedVersions.signed. Skips only on genuine network failure or SKIP_CONTRACT_TESTS=1, so contract drift between the desktop and the server cannot hide behind mocks that agree with themselves.
|
Warning Review limit reached
Next review available in: 16 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (14)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Lands the 4.15.3 hotfix content on master:
Supersedes #3407 and #3406, which will be closed.
Jira: CORE-2409