You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
Repository navigation
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
purgeSignedOutClientCaches's try wraps the whole loop, so one throwing removeItem silently cancels the rest of the sign-out sweep #5777
Found while implementing #5763 (sweepStore's try wraps the whole loop — same defect, sign-in path). Same defect class, different function and different caller (sign-out rather than sign-in), so it is filed rather than fixed on that PR — #5763's own scope note rules out widening into a general refactor of the module, and this function lives in a different file (AuthProvider.tsx, not ActiveOrganizationStorage.ts).
functionpurgeSignedOutClientCaches(): void{if(typeofsessionStorage!=='undefined'){try{// Snapshot the keys first (`Object.keys`) — removing entries during a// live index walk shifts the ones behind it and skips half of them.// Same idiom as the `MarketplacePackagePage` purge loop.for(constkeyofObject.keys(sessionStorage)){if(key.startsWith(METADATA_SEED_CACHE_PREFIX)){sessionStorage.removeItem(key);}}}catch{/* storage unavailable */}}ActiveOrganizationStorage.clear();}
The try wraps the whole loop, not each removeItem. A removeItem that throws on key n aborts the walk (and — unlike sweepStore — this loop is a prefix filter, so it also never reaches the still-unvisited non-matching keys after n, though those were never candidates for removal anyway), so metadata-seed-cache keys after n are never swept and the failure is swallowed.
Why it matters
This is called from AuthProvider on sign-out (purgeSignedOutClientCaches(); before ActiveOrganizationStorage.clear()). Per its own docstring, the entries it clears are MetadataProvider's org-scoped seed cache — a permission-filtered app list that #5198 classifies as a cross-principal disclosure risk, not mere staleness, when it survives into the next session on a shared browser. A partial sweep leaves an arbitrary subset of that cache behind, depending on Object.keys iteration order and where the throw lands.
Reachability
Not demonstrated here either, for the same reason #5731 and #5763 could not reach it from a browser: the state needed is Object.keys succeeding while some removeItem throws. #5763's triage graded that card anyway because the remedy restores an invariant and needs no product decision — the identical argument applies here.
Possible shape
Same remedy as #5763: move the try inside the loop so one uncooperative key costs one key; keep Object.keys(sessionStorage) inside its own guard. Whether a failed sweep should additionally be reported (console.warn, mirroring #5731 and #5763's choice) is the same open question, for the sign-out path this time — #5763's PR discusses why sign-out specifically cannot act on the failure (session already ended).
Scope note
Deliberately not fixed on the #5763 PR — different file, different caller, and #5763's own card text rules out widening into a general storage-error-handling refactor of the module.
Triage: pm:queue + domain:ui, type Bug — inherits #5763's grading and remedy basis: same defect class (whole-loop try), remedy restores an invariant with no product decision, and unproven browser reachability did not gate the sibling, so it does not gate this one. The sign-out variant is the sharper half: the surviving entries are the org-scoped seed cache #5198 classifies as a cross-principal disclosure risk on shared browsers.
Remedy shape per the card: try inside the loop (one uncooperative key costs one key), Object.keys under its own guard; the report-vs-silent question follows #5763's PR discussion for the sign-out path. Same-day churn: #5763's PR merged today — branch from a ref carrying it and re-verify AuthProvider.tsx anchors.
Dispatching this round (R27, concurrency 5). Triage's same-day-churn note is discharged: #5763's PR #5779 merged at 07:56:17Z, so its landed answer to the report-vs-silent question is on main and the dev reads it there rather than from the PR discussion.
{
"issue": 5777,
"status": "done",
"branch": "claude/issue-5777-signout-purge-per-key-try",
"pr": "https://github.com/objectstack-ai/objectui/pull/5816",
"premise_still_valid": true,
"summary": "purgeSignedOutClientCaches() in packages/auth/src/AuthProvider.tsx wrapped its whole removeItem loop in one try, so a removeItem throwing on key n silently aborted the sweep and left every objectui:metadata:* key after n unswept. Moved the try to guard only the Object.keys(sessionStorage) snapshot, gave each removeItem its own try, and added a console.warn naming any unswept keys on a partial sweep -- mirroring #5763's landed sweepStore shape on main (ff2d54717) exactly, including its report-not-quarantine choice, since this function likewise owns no reads for the metadata seed cache it walks.",
"tests": "pnpm exec vitest run packages/auth/src/__tests__/signOut-client-cache-purge-5198.test.tsx --maxWorkers=2 (run from repo root per AGENTS.md, never package-cwd): 6/6 passed on the fix. Reverse-verification on a real commit: committed the fix (da392fbbd), then git checkout HEAD~1 -- packages/auth/src/AuthProvider.tsx to restore the pre-fix whole-loop-try shape and reran the same file -> 1 failed / 5 passed, with the new partial-failure test failing exactly as expected (expected '[{\"name\":\"account\"}]' to be null); the other 5 pass either way since they don't exercise a throwing removeItem. Restored via git checkout claude/issue-5777-signout-purge-per-key-try -- packages/auth/src/AuthProvider.tsx, confirmed git diff HEAD --stat empty, reran -> 6/6 passed. Full package pnpm exec vitest run packages/auth/ --maxWorkers=2 -> 24 files / 251 tests passed, on c0b7876b (PR head). pnpm --filter '@object-ui/auth' type-check (tsc --noEmit && tsc -p tsconfig.test.json, after building the dependency closure with pnpm --filter '@object-ui/auth^...' build) -> clean. node scripts/check-changeset-presence.mjs, check-control-bytes.mjs, check-type-check-coverage.mjs, check-lint-coverage.mjs -> all passed. eslint on the two changed files -> 0 errors, 3 pre-existing warnings unrelated to this diff (react-hooks/set-state-in-effect at lines 300/760/767, outside the edited region). CI on the PR is in_progress at report time; PM to read gate convergence.",
"open_questions": [],
"out_of_scope_findings": []
}
Activity
os-zhuang commentedon Aug 23, 2026
Triage:
pm:queue+domain:ui, type Bug — inherits #5763's grading and remedy basis: same defect class (whole-looptry), remedy restores an invariant with no product decision, and unproven browser reachability did not gate the sibling, so it does not gate this one. The sign-out variant is the sharper half: the surviving entries are the org-scoped seed cache #5198 classifies as a cross-principal disclosure risk on shared browsers.Remedy shape per the card:
tryinside the loop (one uncooperative key costs one key),Object.keysunder its own guard; the report-vs-silent question follows #5763's PR discussion for the sign-out path. Same-day churn: #5763's PR merged today — branch from a ref carrying it and re-verifyAuthProvider.tsxanchors.Generated by Claude Code
claude commentedon Aug 23, 2026
Claim —
domain:uiexecution seat.session_01EuPCi56cnGyykygi3z9w4mclaude/issue-5777-signout-purge-per-key-tryDispatching this round (R27, concurrency 5). Triage's same-day-churn note is discharged: #5763's PR #5779 merged at 07:56:17Z, so its landed answer to the report-vs-silent question is on
mainand the dev reads it there rather than from the PR discussion.Generated by Claude Code
fix(auth): stop purgeSignedOutClientCaches aborting the sign-out swee…
chore(auth): add changeset for #5777 signout purge per-key try fix
os-zhuang commentedon Aug 23, 2026
os-dev-report
{ "issue": 5777, "status": "done", "branch": "claude/issue-5777-signout-purge-per-key-try", "pr": "https://github.com/objectstack-ai/objectui/pull/5816", "premise_still_valid": true, "summary": "purgeSignedOutClientCaches() in packages/auth/src/AuthProvider.tsx wrapped its whole removeItem loop in one try, so a removeItem throwing on key n silently aborted the sweep and left every objectui:metadata:* key after n unswept. Moved the try to guard only the Object.keys(sessionStorage) snapshot, gave each removeItem its own try, and added a console.warn naming any unswept keys on a partial sweep -- mirroring #5763's landed sweepStore shape on main (ff2d54717) exactly, including its report-not-quarantine choice, since this function likewise owns no reads for the metadata seed cache it walks.", "tests": "pnpm exec vitest run packages/auth/src/__tests__/signOut-client-cache-purge-5198.test.tsx --maxWorkers=2 (run from repo root per AGENTS.md, never package-cwd): 6/6 passed on the fix. Reverse-verification on a real commit: committed the fix (da392fbbd), then git checkout HEAD~1 -- packages/auth/src/AuthProvider.tsx to restore the pre-fix whole-loop-try shape and reran the same file -> 1 failed / 5 passed, with the new partial-failure test failing exactly as expected (expected '[{\"name\":\"account\"}]' to be null); the other 5 pass either way since they don't exercise a throwing removeItem. Restored via git checkout claude/issue-5777-signout-purge-per-key-try -- packages/auth/src/AuthProvider.tsx, confirmed git diff HEAD --stat empty, reran -> 6/6 passed. Full package pnpm exec vitest run packages/auth/ --maxWorkers=2 -> 24 files / 251 tests passed, on c0b7876b (PR head). pnpm --filter '@object-ui/auth' type-check (tsc --noEmit && tsc -p tsconfig.test.json, after building the dependency closure with pnpm --filter '@object-ui/auth^...' build) -> clean. node scripts/check-changeset-presence.mjs, check-control-bytes.mjs, check-type-check-coverage.mjs, check-lint-coverage.mjs -> all passed. eslint on the two changed files -> 0 errors, 3 pre-existing warnings unrelated to this diff (react-hooks/set-state-in-effect at lines 300/760/767, outside the edited region). CI on the PR is in_progress at report time; PM to read gate convergence.", "open_questions": [], "out_of_scope_findings": [] }Generated by Claude Code
fix(auth): stop purgeSignedOutClientCaches aborting the sign-out swee…