Skip to content

OUT-4093: Guard localStorage migration when third-party storage is denied - #1407

Closed
cursor[bot] wants to merge 1 commit into
mainfrom
cursor/out-4093-cursor-automated-triage-response-a918
Closed

OUT-4093: Guard localStorage migration when third-party storage is denied#1407
cursor[bot] wants to merge 1 commit into
mainfrom
cursor/out-4093-cursor-automated-triage-response-a918

Conversation

@cursor

@cursor cursor Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Changes

  • Extracted hasAssigneeStorageAccess() helper shared by assignee cache read/write/migrate paths.
  • Guarded migrateAssignees() with storage-access check and try/catch around localStorage calls — this was the only remaining unguarded localStorage usage and the source of the Sentry SecurityError.
  • Removed automatic requestStorageAccess() on mount (requires user gesture; cannot succeed during AssigneeCacheGetter initialization).
  • Added unit tests for denied-storage paths.

Testing Criteria

  • yarn test src/app/_cache/forageStorage.test.ts — all 3 tests pass.

Notes

  • Linear: OUT-4093
  • Root cause: Tasks app runs embedded in a Copilot iframe. When third-party cookies/storage are blocked, migrateAssignees() called localStorage.getItem() without checking document.hasStorageAccess(), throwing SecurityError: Failed to read the 'localStorage' property from 'Window': Access is denied for this document.
  • getAssignees / setAssignees already had guards (OUT-2694 / OUT-2750); migration path was missed when localStorage was replaced with localForage (OUT-2348).
  • Manual intervention if users still see degraded assignee caching: allow third-party cookies for the portal domain, or rely on network fetch (assignees still load via API).

Impact & Surface Area of Change

  • Client-side assignee cache only (AssigneeCacheGetter, AssigneesFetcher).
  • No server-side or API behavior change. App degrades gracefully to network-fetched assignees when storage is unavailable.
Open in Web View Automation 

…nied

migrateAssignees() was the only assignee-cache path still reading
localStorage without checking document.hasStorageAccess(). In the
embedded Copilot iframe this throws SecurityError and surfaces in
Sentry when third-party cookies/storage are blocked.

Extract hasAssigneeStorageAccess() shared by get/set/migrate helpers,
skip migration when access is denied, and wrap localStorage calls in
try/catch. Also stop calling requestStorageAccess() on mount since it
requires a user gesture and cannot succeed during AssigneeCacheGetter
initialization.

Co-authored-by: Neil Raina <[email protected]>
@linear-code

linear-code Bot commented Aug 21, 2026

Copy link
Copy Markdown

OUT-4093

@vercel

vercel Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
tasks-app Ready Ready Preview Aug 21, 2026 8:46pm

Request Review

@priosshrsth

Copy link
Copy Markdown
Collaborator

Closing in favour of #1434, which removes migrateAssignees() instead of guarding it — it shipped in OUT-2348 eleven months ago tagged "remove this after a while" and only migrated a cache, so there's nothing to preserve.

#1434 also drops the hasStorageAccess()/requestStorageAccess() calls entirely rather than extracting a shared helper for them. Your note about requestStorageAccess() needing a user gesture was the right thread to pull: since it can never be granted from a mount effect, and hasStorageAccess() reports unpartitioned cookie access while the cache lives in IndexedDB, the gate only ever aborted the cache — it never enabled it. The surrounding try/catch was already doing the real work.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants