Skip to content

fix: harden supported-versions validation, recovery, and exception scoping - #3405

Closed
jeanfbrito wants to merge 3 commits into
fix/supported-versions-exception-uniqueid-scopefrom
fix/supported-versions-hardening
Closed

fix: harden supported-versions validation, recovery, and exception scoping#3405
jeanfbrito wants to merge 3 commits into
fix/supported-versions-exception-uniqueid-scopefrom
fix/supported-versions-hardening

Conversation

@jeanfbrito

@jeanfbrito jeanfbrito commented Jul 9, 2026

Copy link
Copy Markdown
Member

Stacked on #3404 — retarget to master after it merges.

What

Follow-up hardening pass over the supported-versions subsystem after the exception-scope investigation in #3404. Two independent audits (main-process flow and renderer surfaces) produced the findings below; every fix ships with a regression test.

Fixes

Validation robustness (main process)

  • Wrap the cache/builtin fallback validation in a helper with try/catch. A malformed cached payload could previously reject updateSupportedVersionsData before the error state was dispatched, leaving supportedVersionsFetchState stuck at 'loading' — which suppresses the UnsupportedServer block gate. The error state is now always dispatched and the prior verdict is preserved.
  • Catch rejections at all four fire-and-forget validation call sites (three listeners + the refresh-supported-versions IPC handler).
  • Fall back to the persisted workspace uniqueID when the fresh fetch fails, so the cloud lookup is not skipped for previously-known servers.
  • Revalidate all servers on powerMonitor 'resume' — the window 'online' event does not fire when waking with the same network still connected.

Exception scoping

  • Server, cloud, and cache 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 a diagnostic warning instead of disqualifying the exception. The bundled builtin payload — the only source that could carry another deployment's exceptions — keeps the strict scope requirement.
  • An unknown local uniqueID (e.g. settings.public restricted by API access controls) is never treated as a scope mismatch.
  • exceptions.domain comparison was already made case-insensitive in fix: honor uniqueId-scoped support exceptions on server-signed path #3404.

State integrity

  • WEBVIEW_SERVER_UNIQUE_ID_UPDATED, WEBVIEW_SERVER_VERSION_UPDATED, and WEBVIEW_GIT_COMMIT_HASH_CHANGED reducer cases switched from upsert to update: a late identity dispatch for a server deleted while a validation was in flight can no longer resurrect a ghost server entry.

Renderer

  • SupportedVersionDialog effect dependencies used the imported currentView reducer function (never changes) instead of the state value, so the dialog never re-checked when switching server views. Now selects the real state.
  • Guard getExpirationMessageTranslated against payloads whose i18n dictionary lacks both the user language and en; the unguarded lookup crashed the async check and silently suppressed the expiring-workspace warning dialog.
  • Add a Check again button to the unsupported-workspace screen so validation can be re-triggered without restarting the app (new unsupportedServer.checkAgain en key; other locales fall back).

Enforcement certainty

  • A missing or malformed enforcementStartDate no longer blocks the workspace: an Invalid Date previously failed the future-date comparison and fell through to the unsupported verdict on incomplete payload data. Blocking now requires a valid, past enforcement date.

Cosmetic

  • logRequestError printed a literal ${description} (single-quoted string).

Out of scope, tracked for follow-up

  • Signing-key rotation contingency (single hardcoded RS256 key; needs cloud-side coordination).
  • Expired exception + future enforcementStartDate ⇒ supported (global grace masks a lapsed exception) — needs product confirmation.
  • Test-fixture realism: default mocks include uniqueId/commit/full patch version in /api/info, which real unauthenticated servers do not send.

Tests

  • 143 tests across the four touched suites pass; full repo suite 152 suites / 1602 tests green. tsc --noEmit and yarn lint clean.

Summary by CodeRabbit

  • New Features

    • Added a “Check again” option on the unsupported server dialog to re-run compatibility checks.
  • Bug Fixes

    • Server compatibility checks now refresh when you switch to a different server.
    • Improved handling after sleep/wake so supported-version status is revalidated automatically.
    • Fixed cases where unsupported-server status could behave incorrectly after missing or stale data.
    • Updated unsupported-server messaging to include the new recheck action.

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).
@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Changes

Supported version and server state

Layer / File(s) Summary
Prevent missing-server resurrection
src/servers/reducers.ts, src/servers/reducers/__tests__/servers.spec.ts
Server identity, version, and commit hash actions now update existing entries only, with regression tests for absent URLs.
Apply payload-aware exception scoping
src/servers/supportedVersions/main.ts, src/servers/supportedVersions/main.main.spec.ts
Validation distinguishes server, cloud, and builtin payloads when evaluating exception scopes.
Harden fallback and refresh flows
src/servers/supportedVersions/main.ts, src/servers/supportedVersions/main.main.spec.ts
Fallback validation, persisted unique ID lookup, translation guards, error logging, and resume refresh handling are updated.
Add unsupported-server retry action
src/ui/components/ServersView/*, src/i18n/en.i18n.json
Unsupported servers display a translated check-again action that invokes the refresh IPC channel.
Refresh dialog checks on selection changes
src/ui/components/SupportedVersionDialog/*
The dialog reruns server validation when the selected server changes.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

Suggested labels: type: bug

Sequence Diagram(s)

sequenceDiagram
  participant UnsupportedServer
  participant ipcRenderer
  participant ipcMain
  participant SupportedVersions
  participant Redux
  UnsupportedServer->>ipcRenderer: invoke refresh-supported-versions with serverUrl
  ipcRenderer->>ipcMain: forward refresh request
  ipcMain->>SupportedVersions: update supported versions
  SupportedVersions->>Redux: dispatch supported-version verdict
  Redux->>UnsupportedServer: render updated state
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly reflects the main focus on supported-versions validation, recovery, and exception-scoping fixes.

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/servers/supportedVersions/main.main.spec.ts (1)

2544-2556: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider testing the resume handler's behavior, not just its registration.

The test verifies powerMonitor.on('resume', ...) is called, but doesn't invoke the handler to confirm it triggers updateSupportedVersionsData for all servers. Invoking the registered callback and asserting the refresh calls would strengthen coverage against regressions where the handler body changes but the registration stays the same.

♻️ Proposed enhancement: invoke and verify the resume handler
     it('registers a powerMonitor resume handler when checkSupportedVersionServers runs', async () => {
       const electronMock = jest.requireMock('electron');

       checkSupportedVersionServers();

       expect(electronMock.powerMonitor.on).toHaveBeenCalledWith(
         'resume',
         expect.any(Function)
       );
+
+      // Invoke the registered handler and verify revalidation
+      const resumeHandler = electronMock.powerMonitor.on.mock.calls.find(
        ([event]) => event === 'resume'
      )?.[1];
      expect(resumeHandler).toBeDefined();
+
+      const mockServers = [
        createMockServer({ url: 'https://a.rocket.chat/' }),
        createMockServer({ url: 'https://b.rocket.chat/' }),
      ];
      selectMock.mockReturnValue(mockServers);
+
+      resumeHandler();
+      // Allow microtasks to flush
+      await Promise.resolve();
+
+      // Both servers should trigger a refresh
+      expect(selectMock).toHaveBeenCalled();
     });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/servers/supportedVersions/main.main.spec.ts` around lines 2544 - 2556,
The power resume test in checkSupportedVersionServers only verifies that
powerMonitor.on registers a resume handler, but it does not validate the
handler’s behavior. Update the spec around checkSupportedVersionServers to
capture the resume callback passed to electronMock.powerMonitor.on, invoke it,
and assert that updateSupportedVersionsData is called for all servers (and any
related refresh path) so the test covers the actual revalidation logic rather
than just registration.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/servers/supportedVersions/main.ts`:
- Around line 550-591: `validateFallbackAndDispatch` always falls through to
`WEBVIEW_SERVER_SUPPORTED_VERSIONS_ERROR`, so a successful fallback validation
gets overwritten from success to error. Add an early return after the successful
`WEBVIEW_SERVER_IS_SUPPORTED_VERSION` and `dispatchSupportedVersionsUpdated`
calls, matching the guard used in the server and cloud paths, so the error
dispatch only happens in the catch path or when stale.

---

Nitpick comments:
In `@src/servers/supportedVersions/main.main.spec.ts`:
- Around line 2544-2556: The power resume test in checkSupportedVersionServers
only verifies that powerMonitor.on registers a resume handler, but it does not
validate the handler’s behavior. Update the spec around
checkSupportedVersionServers to capture the resume callback passed to
electronMock.powerMonitor.on, invoke it, and assert that
updateSupportedVersionsData is called for all servers (and any related refresh
path) so the test covers the actual revalidation logic rather than just
registration.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9505ac66-6426-4f40-9b68-f1a1ffe33cc3

📥 Commits

Reviewing files that changed from the base of the PR and between 615d79d and 15bf8a3.

📒 Files selected for processing (10)
  • src/i18n/en.i18n.json
  • src/servers/reducers.ts
  • src/servers/reducers/__tests__/servers.spec.ts
  • src/servers/supportedVersions/main.main.spec.ts
  • src/servers/supportedVersions/main.ts
  • src/ui/components/ServersView/ServerPane.tsx
  • src/ui/components/ServersView/UnsupportedServer.spec.tsx
  • src/ui/components/ServersView/UnsupportedServer.tsx
  • src/ui/components/SupportedVersionDialog/index.spec.tsx
  • src/ui/components/SupportedVersionDialog/index.tsx
📜 Review details
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Use TypeScript for all new code unless explicitly told otherwise.
Use Fuselage components for all UI work; only create custom components when Fuselage does not provide what is needed.
Import UI components from @rocket.chat/fuselage.
Check Theme.d.ts for valid color tokens before using Fuselage theme colors.
Use optional chaining with fallbacks for platform-specific APIs, especially Linux-only process APIs like process.getuid(), process.getgid(), process.geteuid(), and process.getegid().
Only mock platform-specific APIs when defensive coding is not possible.
Use TypeScript strict mode.
Use React functional components with hooks.
Redux actions must follow the Flux Standard Action (FSA) pattern.
Use camelCase for file names and PascalCase for components.

**/*.{ts,tsx}: Use TypeScript for new code unless explicitly told otherwise.
Use Fuselage components from @rocket.chat/fuselage for UI work unless the design requires something Fuselage does not provide.
Check Theme.d.ts for valid color tokens before using Fuselage colors.
Verify library props, APIs, and tokens against official docs or local .d.ts files instead of assuming.
Use React functional components with hooks.
Redux actions follow FSA shape.
Use camelCase for file names and PascalCase for components.
Prefer clear names over unnecessary comments.
Prefer editing existing files over creating new abstractions unless the new abstraction removes real complexity or matches an existing pattern.

Files:

  • src/ui/components/ServersView/ServerPane.tsx
  • src/ui/components/ServersView/UnsupportedServer.spec.tsx
  • src/servers/reducers/__tests__/servers.spec.ts
  • src/ui/components/SupportedVersionDialog/index.tsx
  • src/ui/components/SupportedVersionDialog/index.spec.tsx
  • src/servers/reducers.ts
  • src/ui/components/ServersView/UnsupportedServer.tsx
  • src/servers/supportedVersions/main.main.spec.ts
  • src/servers/supportedVersions/main.ts
**/*.spec.tsx

📄 CodeRabbit inference engine (CLAUDE.md)

Use *.spec.tsx for renderer process tests.

Files:

  • src/ui/components/ServersView/UnsupportedServer.spec.tsx
  • src/ui/components/SupportedVersionDialog/index.spec.tsx
**/*.spec.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Renderer specs use *.spec.ts / *.spec.tsx.

Files:

  • src/ui/components/ServersView/UnsupportedServer.spec.tsx
  • src/servers/reducers/__tests__/servers.spec.ts
  • src/ui/components/SupportedVersionDialog/index.spec.tsx
  • src/servers/supportedVersions/main.main.spec.ts
**/*.spec.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Use *.spec.ts for renderer process tests.

Files:

  • src/servers/reducers/__tests__/servers.spec.ts
  • src/servers/supportedVersions/main.main.spec.ts
**/*.main.spec.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Use *.main.spec.ts for main process tests.

Main-process specs use *.main.spec.ts.

Files:

  • src/servers/supportedVersions/main.main.spec.ts
src/*/*/*.spec.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Renderer specs must live in a Jest-matched nested path, such as src/<module>/<subdir>/*.spec.ts(x); flat src/<module>/*.spec.ts files are not discovered by the current testMatch.

Files:

  • src/servers/supportedVersions/main.main.spec.ts
🧠 Learnings (1)
📚 Learning: 2026-06-26T18:14:15.295Z
Learnt from: jeanfbrito
Repo: RocketChat/Rocket.Chat.Electron PR: 3358
File: src/i18n/it-IT.i18n.json:39-42
Timestamp: 2026-06-26T18:14:15.295Z
Learning: In the i18n JSON files, the translation key `minimizeOnClose.disabledHint` is intentionally displayed when `isTrayIconEnabled` is true and the minimize-on-close toggle is disabled. The hint text should therefore instruct the user to disable the tray icon to make the setting available. During reviews, don’t “correct” this translation for seeming mismatches with the toggle state—first confirm it matches the component’s intended behavior; only update the wording if the underlying product logic/UX requirement changes.

Applied to files:

  • src/i18n/en.i18n.json
🔇 Additional comments (18)
src/servers/reducers.ts (1)

162-165: LGTM!

Also applies to: 184-188, 220-223

src/servers/reducers/__tests__/servers.spec.ts (1)

195-205: LGTM!

Also applies to: 241-251, 319-329

src/servers/supportedVersions/main.ts (6)

345-383: LGTM!


302-304: LGTM!


85-85: LGTM!


5-5: LGTM!


710-718: LGTM!


801-841: LGTM!

src/servers/supportedVersions/main.main.spec.ts (4)

478-517: LGTM!

Also applies to: 1976-2006, 2027-2063, 2089-2116, 2114-2141


2449-2499: LGTM!


2501-2526: LGTM!


2527-2543: LGTM!

src/ui/components/ServersView/UnsupportedServer.tsx (1)

15-27: LGTM!

Also applies to: 37-40, 76-78

src/ui/components/ServersView/ServerPane.tsx (1)

237-237: LGTM!

src/i18n/en.i18n.json (1)

492-493: LGTM!

src/ui/components/ServersView/UnsupportedServer.spec.tsx (1)

1-96: LGTM!

src/ui/components/SupportedVersionDialog/index.tsx (1)

18-18: LGTM!

Also applies to: 28-38, 142-144

src/ui/components/SupportedVersionDialog/index.spec.tsx (1)

1-9: LGTM!

Also applies to: 171-203

Comment on lines +550 to +591
// Validates the fallback (cache/builtin) payload and dispatches the verdict.
// isServerVersionSupported can throw on a malformed cached/builtin payload
// (e.g. `versions` not an array). Left unguarded, that throw would reject
// updateSupportedVersionsData before WEBVIEW_SERVER_SUPPORTED_VERSIONS_ERROR
// is dispatched, leaving supportedVersionsFetchState stuck at 'loading' —
// which suppresses the UnsupportedServer block gate (fail-open). On failure,
// only the error state is dispatched; the prior verdict is left untouched.
const validateFallbackAndDispatch = async (
server: Server,
serverUrl: string,
fallbackVersions: SupportedVersions,
fallbackSource: 'cloud' | 'builtin',
freshCommitHash: string | undefined,
isStale: () => boolean
): Promise<void> => {
try {
const fallbackSupported = await isServerVersionSupported(
server,
fallbackVersions,
freshCommitHash,
fallbackSource
);
if (isStale()) return;
dispatch({
type: WEBVIEW_SERVER_IS_SUPPORTED_VERSION,
payload: {
url: server.url,
isSupportedVersion: fallbackSupported.supported,
},
});
dispatchSupportedVersionsUpdated(server.url, fallbackVersions, {
source: fallbackSource,
});
} catch (error) {
console.error('Error validating fallback supported versions:', error);
}
if (isStale()) return;
dispatch({
type: WEBVIEW_SERVER_SUPPORTED_VERSIONS_ERROR,
payload: { url: serverUrl },
});
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🔴 Critical | ⚡ Quick win

Critical: validateFallbackAndDispatch dispatches error state on the success path, overriding supportedVersionsFetchState: 'success' with 'error'.

After a successful validation, the try block dispatches WEBVIEW_SERVER_IS_SUPPORTED_VERSION and WEBVIEW_SERVER_SUPPORTED_VERSIONS_UPDATED (which sets supportedVersionsFetchState: 'success'), but there is no return before the post-try-catch WEBVIEW_SERVER_SUPPORTED_VERSIONS_ERROR dispatch, which overrides the fetch state to 'error'.

Both the server path (line 682) and cloud path (line 747) correctly return after dispatching their verdict. The fallback path is the only one missing this guard. The function's own comment states "On failure, only the error state is dispatched; the prior verdict is left untouched," but the implementation contradicts this for the success path.

The existing FIX-1 test only covers the failure path (malformed payload), so this bug goes undetected.

🐛 Proposed fix: add `return` after success-path dispatches
     dispatchSupportedVersionsUpdated(server.url, fallbackVersions, {
       source: fallbackSource,
     });
+    return;
   } catch (error) {
     console.error('Error validating fallback supported versions:', error);
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Validates the fallback (cache/builtin) payload and dispatches the verdict.
// isServerVersionSupported can throw on a malformed cached/builtin payload
// (e.g. `versions` not an array). Left unguarded, that throw would reject
// updateSupportedVersionsData before WEBVIEW_SERVER_SUPPORTED_VERSIONS_ERROR
// is dispatched, leaving supportedVersionsFetchState stuck at 'loading' —
// which suppresses the UnsupportedServer block gate (fail-open). On failure,
// only the error state is dispatched; the prior verdict is left untouched.
const validateFallbackAndDispatch = async (
server: Server,
serverUrl: string,
fallbackVersions: SupportedVersions,
fallbackSource: 'cloud' | 'builtin',
freshCommitHash: string | undefined,
isStale: () => boolean
): Promise<void> => {
try {
const fallbackSupported = await isServerVersionSupported(
server,
fallbackVersions,
freshCommitHash,
fallbackSource
);
if (isStale()) return;
dispatch({
type: WEBVIEW_SERVER_IS_SUPPORTED_VERSION,
payload: {
url: server.url,
isSupportedVersion: fallbackSupported.supported,
},
});
dispatchSupportedVersionsUpdated(server.url, fallbackVersions, {
source: fallbackSource,
});
} catch (error) {
console.error('Error validating fallback supported versions:', error);
}
if (isStale()) return;
dispatch({
type: WEBVIEW_SERVER_SUPPORTED_VERSIONS_ERROR,
payload: { url: serverUrl },
});
};
// Validates the fallback (cache/builtin) payload and dispatches the verdict.
// isServerVersionSupported can throw on a malformed cached/builtin payload
// (e.g. `versions` not an array). Left unguarded, that throw would reject
// updateSupportedVersionsData before WEBVIEW_SERVER_SUPPORTED_VERSIONS_ERROR
// is dispatched, leaving supportedVersionsFetchState stuck at 'loading' —
// which suppresses the UnsupportedServer block gate (fail-open). On failure,
// only the error state is dispatched; the prior verdict is left untouched.
const validateFallbackAndDispatch = async (
server: Server,
serverUrl: string,
fallbackVersions: SupportedVersions,
fallbackSource: 'cloud' | 'builtin',
freshCommitHash: string | undefined,
isStale: () => boolean
): Promise<void> => {
try {
const fallbackSupported = await isServerVersionSupported(
server,
fallbackVersions,
freshCommitHash,
fallbackSource
);
if (isStale()) return;
dispatch({
type: WEBVIEW_SERVER_IS_SUPPORTED_VERSION,
payload: {
url: server.url,
isSupportedVersion: fallbackSupported.supported,
},
});
dispatchSupportedVersionsUpdated(server.url, fallbackVersions, {
source: fallbackSource,
});
return;
} catch (error) {
console.error('Error validating fallback supported versions:', error);
}
if (isStale()) return;
dispatch({
type: WEBVIEW_SERVER_SUPPORTED_VERSIONS_ERROR,
payload: { url: serverUrl },
});
};
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/servers/supportedVersions/main.ts` around lines 550 - 591,
`validateFallbackAndDispatch` always falls through to
`WEBVIEW_SERVER_SUPPORTED_VERSIONS_ERROR`, so a successful fallback validation
gets overwritten from success to error. Add an early return after the successful
`WEBVIEW_SERVER_IS_SUPPORTED_VERSION` and `dispatchSupportedVersionsUpdated`
calls, matching the guard used in the server and cloud paths, so the error
dispatch only happens in the catch path or when stale.

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.
@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
putComment timed out

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant