Skip to content

159 auth user active sessions#242

Merged
InfinityBowman merged 10 commits into
mainfrom
159-auth---user-active-sessions
Jan 7, 2026
Merged

159 auth user active sessions#242
InfinityBowman merged 10 commits into
mainfrom
159-auth---user-active-sessions

Conversation

@InfinityBowman
Copy link
Copy Markdown
Owner

@InfinityBowman InfinityBowman commented Jan 7, 2026

Summary by CodeRabbit

  • New Features

    • Added Active Sessions management in Security Settings, allowing users to view all logged-in sessions across devices and revoke individual sessions or all other sessions.
  • Bug Fixes

    • Resolved session revocation and SSRF protection for API endpoints through enhanced security mechanisms.
  • Chores

    • Updated internal component imports and refactored configuration settings.

✏️ Tip: You can customize this high-level summary in your review settings.

@InfinityBowman InfinityBowman linked an issue Jan 7, 2026 that may be closed by this pull request
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jan 7, 2026

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

📝 Walkthrough

Walkthrough

This PR introduces an ESLint rule enforcing correct @corates/ui component usage (prestyled vs. primitive), integrates it into the ESLint configuration, adds session management functionality to the auth store with public API exports, and creates a SessionManagement UI component for listing and revoking user sessions across devices. It also updates the security audit documentation to reflect resolved implementation items.

Changes

Cohort / File(s) Summary
ESLint Rule & Configuration
eslint-rules/corates-ui-imports.js, eslint-rules/index.js, eslint.config.js
Introduces new ESLint rule mapping prestyled to primitive @corates/ui components, detects misuse in JSX and regular contexts, exports via rules index, and wires into ESLint config with additional @ark-ui/solid import restrictions and UI package override
Session Management API
packages/web/src/api/auth-client.js, packages/web/src/api/better-auth-store.js
Exports four session management methods (listSessions, revokeSession, revokeOtherSessions, revokeSessions) from auth client; adds corresponding store methods with error handling and cache-clearing logic on revoke-all
Session Management UI
packages/web/src/components/settings/pages/SecuritySettings.jsx, packages/web/src/components/settings/pages/SessionManagement.jsx
Adds new SessionManagement component with session listing, per-session and bulk revoke actions, user agent parsing, IP masking, device deduplication, and confirmation dialogs; integrates into SecuritySettings
Minor Component Updates
packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsx, packages/web/src/components/settings/SettingsLayout.jsx
Replaces Dialog import with DialogPrimitive alias; comments out mobile toggle handler and reformats inline children rendering
Documentation
packages/docs/audits/security-audit-2026-01.md
Updates security audit to reflect resolved session revocation via Better Auth APIs, SSRF protection implementation, webhook livemode checks, and adjusted security posture score

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant SM as SessionManagement UI
    participant Store as Better Auth Store
    participant Client as Auth Client
    participant API as Backend API
    
    User->>SM: Click revoke session
    SM->>SM: Show confirmation (if revokeAll)
    SM->>SM: Set revoking state
    
    alt Revoke Single Session
        SM->>Store: revokeSessionByToken(token)
    else Revoke All Others
        SM->>Store: revokeAllOtherSessions()
    else Revoke All (Sign out everywhere)
        SM->>Store: revokeAllSessions()
    end
    
    Store->>Client: Call _revokeSession(s)
    Client->>API: POST revoke endpoint
    API-->>Client: Success/Error response
    
    Client-->>Store: Return result
    
    alt Error
        Store->>Store: Set authError
        Store-->>SM: Throw error
        SM->>SM: Catch & show error toast
    else Success
        alt Revoke All Sessions
            Store->>Store: Clear cached user/avatar/auth
        end
        Store-->>SM: Return success
        SM->>SM: Refetch active sessions
        SM->>Store: listActiveSessions()
        Store->>Client: _listSessions()
        Client->>API: Fetch sessions
        API-->>Client: Sessions list
        Client-->>Store: Return sessions
        Store-->>SM: Return sessions
        SM->>SM: Update UI with new list
    end
    
    SM->>SM: Clear revoking state
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~35 minutes

Possibly related PRs

  • 72 offline fixes #73 — Main PR adds ESLint rule enforcing @corates/ui component imports and distinguishing prestyled from primitive usage patterns.
  • 70 zag package #71 — Introduces @corates/ui package and migrates codebase to use its components, directly aligned with the ESLint rule enforcement scope.
🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title check ❓ Inconclusive The PR title '159 auth user active sessions' is vague and uses non-descriptive formatting with extra spacing. It reads more like a ticket reference than a meaningful change summary, lacking clarity about the actual implementation or feature being added. Revise the title to clearly describe the primary change, such as 'Add user session management and revocation UI' or 'Implement active sessions display with revoke functionality'.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 82.35% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom Pre-merge checks in the settings.


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 and usage tips.

@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented Jan 7, 2026

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
corates c293aa2 Commit Preview URL Jan 07 2026, 07:50 AM

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In @packages/docs/audits/security-audit-2026-01.md:
- Around line 1122-1155: The audit claims a working isBlockedHost-based SSRF
defense (blocking hostnames like "localhost" and "metadata.google.internal",
regexes for 127/10/172.16-31/192.168/169.254 and IPv6, numeric-decimal IPs, and
redirect validation) but the pdf-proxy handler actually lacks these checks;
either implement the protections in the pdf-proxy endpoint handler (add an
isBlockedHost(hostname) utility used before fetching and when following
redirects to check parsedUrl.hostname and redirectUrl.hostname, implement
numeric-decimal IP detection/resolution, the listed regex/IP ranges and explicit
blocked hostnames, and ensure redirect validation increments redirect count and
rechecks targets) or update the audit doc to remove the false claims and
document the real current behavior (keep references to isBlockedHost,
parsedUrl.hostname, redirectUrl.hostname and the pdf-proxy handler to locate
where to add or remove the described protections).

In @packages/web/src/api/better-auth-store.js:
- Around line 676-687: The revokeAllSessions function currently calls
_revokeSessions and clears local in-memory state (saveCachedAuth, setCachedUser,
setCachedAvatarUrl) but does not perform the full signout cleanup; update
revokeAllSessions to mirror signout(): after successful _revokeSessions() call
invoke clearAvatarCache(), call queryClient.clear(), call
clearPersistedQueryCache(), trigger a refetch of the session (e.g.,
refetchSession()) to immediately reset state, and then clear in-memory caches
and avatar like existing saveCachedAuth(null), setCachedUser(null),
setCachedAvatarUrl(null); keep the existing error handling that sets
setAuthError(err.message) and rethrows from the catch that references
_revokeSessions.
🧹 Nitpick comments (3)
packages/web/src/components/settings/SettingsLayout.jsx (1)

69-69: Remove commented-out code or document intent.

The toggleMobileSidebar function is commented out but not removed. If this is a temporary change pending future mobile UI work, add a TODO comment explaining the intent. Otherwise, remove it to reduce code clutter.

🔎 Proposed fix
-  // const toggleMobileSidebar = () => setMobileSidebarOpen(open => !open);
   const closeMobileSidebar = () => setMobileSidebarOpen(false);
eslint.config.js (1)

244-250: Consider removing redundant pattern.

The patterns array with @ark-ui/solid/* is redundant since all specific subpaths are already listed in the paths array above. ESLint will match the specific paths first, and the generic pattern provides no additional coverage.

🔎 Proposed fix
         },
       ],
-      patterns: [
-        {
-          group: ['@ark-ui/solid/*'],
-          message:
-            'Import from @corates/ui instead. Use ComponentName for prestyled or ComponentNamePrimitive for the Ark UI primitive.',
-        },
-      ],
     },
   ],
packages/web/src/components/settings/pages/SessionManagement.jsx (1)

56-72: Consider handling edge case for invalid dates.

The function could return unexpected results if date is an invalid date string (resulting in NaN from date arithmetic).

🔎 Proposed fix
 function formatRelativeTime(date) {
   if (!date) return 'Unknown';
 
   const now = new Date();
   const then = new Date(date);
+  if (isNaN(then.getTime())) return 'Unknown';
+  
   const diffMs = now - then;
+  if (diffMs < 0) return 'Just now'; // Handle future dates gracefully
+  
   const diffMins = Math.floor(diffMs / 60000);
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1ee6b68 and 02c39c8.

📒 Files selected for processing (10)
  • eslint-rules/corates-ui-imports.js
  • eslint-rules/index.js
  • eslint.config.js
  • packages/docs/audits/security-audit-2026-01.md
  • packages/web/src/api/auth-client.js
  • packages/web/src/api/better-auth-store.js
  • packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsx
  • packages/web/src/components/settings/SettingsLayout.jsx
  • packages/web/src/components/settings/pages/SecuritySettings.jsx
  • packages/web/src/components/settings/pages/SessionManagement.jsx
🧰 Additional context used
📓 Path-based instructions (18)
packages/web/src/**/*.{js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/form-state.mdc)

packages/web/src/**/*.{js,jsx}: Save form state to IndexedDB before initiating OAuth redirects (Google Drive, ORCID) using saveFormState() with form type ('createProject' or 'addStudies') and serializable state only
Only save serializable data to IndexedDB—exclude File objects, ArrayBuffers, functions, and other non-serializable objects from form state persistence
Restore form state after OAuth redirects by checking URL restore params with getRestoreParamsFromUrl(), retrieving saved state with getFormState(), restoring to form, clearing saved state with clearFormState(), and clearing URL params with clearRestoreParamsFromUrl()
For temporary File object storage during OAuth flows (e.g., pending PDFs), use projectStore.setPendingProjectData() instead of IndexedDB, as File objects cannot be serialized
Add restore parameters to the URL after OAuth redirects in the format '?restore=&projectId=' to signal form state restoration on mount
Clear URL restore parameters after form state restoration by calling clearRestoreParamsFromUrl() to prevent stale restoration attempts on subsequent navigation
Form state persistence library functions (saveFormState, getFormState, clearFormState, getRestoreParamsFromUrl, clearRestoreParamsFromUrl) are implemented in packages/web/src/lib/formStatePersistence.js and should be imported from @/lib/formStatePersistence.js

Files:

  • packages/web/src/api/auth-client.js
  • packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsx
  • packages/web/src/components/settings/pages/SecuritySettings.jsx
  • packages/web/src/components/settings/pages/SessionManagement.jsx
  • packages/web/src/components/settings/SettingsLayout.jsx
  • packages/web/src/api/better-auth-store.js
packages/web/src/**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/pdf-handling.mdc)

packages/web/src/**/*.{js,jsx,ts,tsx}: Always use uploadPdf from @api/pdf-api.js for uploading PDF files. Pass object with projectId, studyId, tag ('primary' or 'supplementary'), and fileName
Validate PDF files on frontend by checking file.type includes 'pdf' and file.size is within MAX_PDF_SIZE limit (full validation is done on backend)
Use cachePdf and getCachedPdf from @primitives/pdfCache.js for caching PDF data in IndexedDB
Implement PDF caching strategy: check cache first, download from server if not cached, then cache the downloaded PDF
Store only PDF metadata in Yjs (id, name, size, tag, uploadedAt, uploadedBy), never store PDF binary data in Yjs as it is too large
Use importFromGoogleDrive from @api/google-drive.js for importing PDFs from Google Drive. Pass fileId, projectId, studyId, and tag
Save form state using saveFormState from @/lib/formStatePersistence.js before triggering OAuth redirects for Google Drive
Use addPdfToStudy operation from useProject hook to add PDFs to a study, passing id, name, size, tag, uploadedAt, and uploadedBy
Use removePdfFromStudy operation from useProject hook to remove PDFs from a study
Use pdfPreviewStore from @/stores/pdfPreviewStore.js for managing PDF preview state (openPreview, closePreview, getPreview methods)
Use downloadPdf from @api/pdf-api.js to download PDFs from server, then cache the result using cachePdf
Always cache PDFs after download and check cache before downloading to avoid redundant downloads
Use PDF operations from useProject hook instead of bypassing through direct API calls

packages/web/src/**/*.{js,jsx,ts,tsx}: For UI icons, use solid-icons library or SVGs only (never emojis)
Use import aliases from jsconfig.json (see ui-components.mdc)

Files:

  • packages/web/src/api/auth-client.js
  • packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsx
  • packages/web/src/components/settings/pages/SecuritySettings.jsx
  • packages/web/src/components/settings/pages/SessionManagement.jsx
  • packages/web/src/components/settings/SettingsLayout.jsx
  • packages/web/src/api/better-auth-store.js
{packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/solidjs.mdc)

{packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx}: Use createSignal for simple reactive values in SolidJS components
Use createStore for complex objects and arrays that need granular reactivity in SolidJS
Use createMemo for computed/derived values that depend on reactive state in SolidJS
Always clean up SolidJS effects that create subscriptions or timers using onCleanup
Import stores directly in components and use store read/write action pattern - read from store, write via actions store
Prefer derived state with createMemo or signals over effects whenever possible
Use local createSignal or createStore for local component state; use external stores for shared/cross-feature state

Files:

  • packages/web/src/api/auth-client.js
  • packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsx
  • packages/web/src/components/settings/pages/SecuritySettings.jsx
  • packages/web/src/components/settings/pages/SessionManagement.jsx
  • packages/web/src/components/settings/SettingsLayout.jsx
  • packages/web/src/api/better-auth-store.js
packages/{web,ui}/**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)

packages/{web,ui}/**/*.{js,jsx,ts,tsx}: Import UI components from '@corates/ui' package instead of local components directories
Use solid-icons library for icons instead of emojis or other icon sources
Use Tailwind CSS classes for styling UI components
Apply responsive design using mobile-first approach with Tailwind CSS

Files:

  • packages/web/src/api/auth-client.js
  • packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsx
  • packages/web/src/components/settings/pages/SecuritySettings.jsx
  • packages/web/src/components/settings/pages/SessionManagement.jsx
  • packages/web/src/components/settings/SettingsLayout.jsx
  • packages/web/src/api/better-auth-store.js
packages/web/**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)

Use import aliases from jsconfig.json (e.g., @/, @components/, @auth-ui/, @checklist-ui/, @project-ui/, @routes/, @primitives/, @api/, @config/, @lib/) instead of relative paths

Files:

  • packages/web/src/api/auth-client.js
  • packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsx
  • packages/web/src/components/settings/pages/SecuritySettings.jsx
  • packages/web/src/components/settings/pages/SessionManagement.jsx
  • packages/web/src/components/settings/SettingsLayout.jsx
  • packages/web/src/api/better-auth-store.js
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/yjs-sync.mdc)

**/*.{js,jsx,ts,tsx}: Use the useProject hook for managing Yjs connections with reference counting instead of creating Y.Doc instances directly
Never create Y.Doc instances directly; always use the connection registry managed by useProject
Access Y.Doc connection state via projectStore.getConnectionState(projectId) instead of checking connection state directly
Read Yjs-synced data from projectStore (using getStudies, getChecklist, etc.) rather than accessing Y.Doc maps/arrays directly
Use operation functions from useProject or projectActionsStore for writing data instead of directly modifying Y.Doc
Don't store Y.Doc references in component state; always retrieve the connection through useProject
Handle connection cleanup via onCleanup() in Solid.js components or equivalent cleanup patterns, calling disconnect() when the component unmounts

**/*.{js,jsx,ts,tsx}: For UI icons, use solid-icons library or SVGs only (never emojis)
Prefer modern ES6+ syntax and features
Use import aliases from jsconfig.json (see ui-components.mdc)
Group related components in subdirectories with barrel exports
Use Ark UI components from @corates/ui package, NOT local components
Use solid-icons icon library (e.g., solid-icons/bi, solid-icons/fi) for icons
Comments should explain WHY something is being done, not narrate what the code does
Use comments to explain why a particular approach or workaround was chosen
Use comments to clarify intent when code could be misread or misunderstood
Use comments to provide context from external systems, specs, or requirements
Use comments to document assumptions, edge cases, or limitations
Do NOT narrate what the code is doing in comments
Do NOT duplicate function or variable names in plain English in comments
Do NOT leave stale comments that contradict the code
Do NOT reference removed or obsolete code paths in comments

**/*.{js,jsx,ts,tsx}: Prefer modern ES6+ syntax and features
Comments should not repeat what the code is saying. Rese...

Files:

  • packages/web/src/api/auth-client.js
  • eslint.config.js
  • packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsx
  • eslint-rules/corates-ui-imports.js
  • packages/web/src/components/settings/pages/SecuritySettings.jsx
  • packages/web/src/components/settings/pages/SessionManagement.jsx
  • packages/web/src/components/settings/SettingsLayout.jsx
  • eslint-rules/index.js
  • packages/web/src/api/better-auth-store.js
**/*.{js,jsx,ts,tsx,css,scss}

📄 CodeRabbit inference engine (.cursor/rules/corates.mdc)

Ensure browser compatibility (Safari is usually problematic)

Files:

  • packages/web/src/api/auth-client.js
  • eslint.config.js
  • packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsx
  • eslint-rules/corates-ui-imports.js
  • packages/web/src/components/settings/pages/SecuritySettings.jsx
  • packages/web/src/components/settings/pages/SessionManagement.jsx
  • packages/web/src/components/settings/SettingsLayout.jsx
  • eslint-rules/index.js
  • packages/web/src/api/better-auth-store.js
packages/web/src/**

📄 CodeRabbit inference engine (.cursor/rules/organizations.mdc)

packages/web/src/**: Use human-readable slug in frontend URLs: /orgs/:orgSlug/...
Use orgId (UUID) for API calls, not orgSlug, when making fetch requests to backend endpoints

Files:

  • packages/web/src/api/auth-client.js
  • packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsx
  • packages/web/src/components/settings/pages/SecuritySettings.jsx
  • packages/web/src/components/settings/pages/SessionManagement.jsx
  • packages/web/src/components/settings/SettingsLayout.jsx
  • packages/web/src/api/better-auth-store.js
packages/{web,ui}/src/**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Group related components in subdirectories with barrel exports

Files:

  • packages/web/src/api/auth-client.js
  • packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsx
  • packages/web/src/components/settings/pages/SecuritySettings.jsx
  • packages/web/src/components/settings/pages/SessionManagement.jsx
  • packages/web/src/components/settings/SettingsLayout.jsx
  • packages/web/src/api/better-auth-store.js
packages/{workers,web}/src/**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use Better-Auth for authentication and user management

Files:

  • packages/web/src/api/auth-client.js
  • packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsx
  • packages/web/src/components/settings/pages/SecuritySettings.jsx
  • packages/web/src/components/settings/pages/SessionManagement.jsx
  • packages/web/src/components/settings/SettingsLayout.jsx
  • packages/web/src/api/better-auth-store.js
packages/web/src/**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

packages/web/src/**/*.{js,ts,jsx,tsx}: Use createStore for complex state objects
Use createMemo for derived values

Files:

  • packages/web/src/api/auth-client.js
  • packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsx
  • packages/web/src/components/settings/pages/SecuritySettings.jsx
  • packages/web/src/components/settings/pages/SessionManagement.jsx
  • packages/web/src/components/settings/SettingsLayout.jsx
  • packages/web/src/api/better-auth-store.js
packages/web/**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)

packages/web/**/*.{js,ts,jsx,tsx}: Use apiFetch for all frontend API calls instead of raw fetch to automatically handle JSON parsing, errors, and toast notifications
Use handleFetchError for wrapping legacy raw fetch calls in frontend code (legacy pattern, prefer apiFetch)
Use error utility functions like isErrorCode from error-utils to check specific error types instead of direct string comparisons

Files:

  • packages/web/src/api/auth-client.js
  • packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsx
  • packages/web/src/components/settings/pages/SecuritySettings.jsx
  • packages/web/src/components/settings/pages/SessionManagement.jsx
  • packages/web/src/components/settings/SettingsLayout.jsx
  • packages/web/src/api/better-auth-store.js
packages/{web,workers}/**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)

Never throw string literals; always throw Error objects or return domain errors from API routes

Files:

  • packages/web/src/api/auth-client.js
  • packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsx
  • packages/web/src/components/settings/pages/SecuritySettings.jsx
  • packages/web/src/components/settings/pages/SessionManagement.jsx
  • packages/web/src/components/settings/SettingsLayout.jsx
  • packages/web/src/api/better-auth-store.js
packages/web/src/**/*.{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/pdf-handling.mdc)

Use PdfViewer component from @/components/checklist-ui/pdf/PdfViewer.jsx for displaying PDFs, passing pdfData as ArrayBuffer, fileName, readOnly, and onPageChange

packages/web/src/**/*.{jsx,tsx}: Do NOT prop-drill application state - Import stores directly where needed
Do NOT destructure props - Access props.field directly or wrap in function: () => props.field
Components should receive at most 1-5 props (local config only, not shared state)
Move business logic to stores, utilities, or primitives (not components)

Files:

  • packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsx
  • packages/web/src/components/settings/pages/SecuritySettings.jsx
  • packages/web/src/components/settings/pages/SessionManagement.jsx
  • packages/web/src/components/settings/SettingsLayout.jsx
{packages/web/**,packages/landing/**}/**/*.{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/solidjs.mdc)

{packages/web/**,packages/landing/**}/**/*.{jsx,tsx}: NEVER destructure props in SolidJS components - access props directly or wrap in functions to maintain reactivity
Use external stores in packages/web/src/stores/ for shared/cross-feature state instead of prop-drilling
Keep SolidJS components lean and focused on rendering - move business logic to stores, primitives, or utilities
Create reusable logic in primitives (hooks) in packages/web/src/primitives/ and import them into components
Use Solid's Show component for conditional rendering instead of ternary operators
Use Solid's For component for rendering lists instead of Array.map()
Use the children helper when manipulating props.children in SolidJS components

Files:

  • packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsx
  • packages/web/src/components/settings/pages/SecuritySettings.jsx
  • packages/web/src/components/settings/pages/SessionManagement.jsx
  • packages/web/src/components/settings/SettingsLayout.jsx
packages/web/**/*.{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/corates.mdc)

packages/web/**/*.{jsx,tsx}: Do NOT prop-drill application state in SolidJS - import stores directly where needed
Do NOT destructure props in SolidJS - access props.field directly or wrap in function: () => props.field
Shared state lives in external stores under packages/web/src/stores/
SolidJS components should receive at most 1-5 props (local config only, not shared state)
Use createStore for complex state objects in SolidJS
Use createMemo for derived values in SolidJS
Move business logic to stores, utilities, or primitives - not components
Frontend uses orgSlug in URLs (/orgs/:orgSlug/...) for readability

Use createFormErrorSignals for form error handling in frontend forms to manage field-level and global error states

Files:

  • packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsx
  • packages/web/src/components/settings/pages/SecuritySettings.jsx
  • packages/web/src/components/settings/pages/SessionManagement.jsx
  • packages/web/src/components/settings/SettingsLayout.jsx
packages/{web,landing,docs}/src/**/*.{jsx,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

packages/{web,landing,docs}/src/**/*.{jsx,tsx}: Use Ark UI components from @corates/ui package, NOT local components
Use solid-icons for icon imports (e.g., solid-icons/bi, solid-icons/fi)

Files:

  • packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsx
  • packages/web/src/components/settings/pages/SecuritySettings.jsx
  • packages/web/src/components/settings/pages/SessionManagement.jsx
  • packages/web/src/components/settings/SettingsLayout.jsx
packages/docs/audits/**

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Place plans/audits in packages/docs/audits/ directory

Files:

  • packages/docs/audits/security-audit-2026-01.md
🧠 Learnings (37)
📓 Common learnings
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-12-27T03:02:33.023Z
Learning: Applies to packages/{web,ui}/**/*.{js,jsx,ts,tsx} : Import UI components from 'corates/ui' package instead of local components directories
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-06T18:29:08.736Z
Learning: Applies to packages/{web,landing,docs}/src/**/*.{jsx,tsx} : Use Ark UI components from `corates/ui` package, NOT local components
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-06T18:29:08.736Z
Learning: Applies to packages/{workers,web}/src/**/*.{js,ts,jsx,tsx} : Use Better-Auth for authentication and user management
📚 Learning: 2025-12-27T03:02:33.023Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-12-27T03:02:33.023Z
Learning: Applies to packages/{web,ui}/**/*.{js,jsx,ts,tsx} : Import UI components from 'corates/ui' package instead of local components directories

Applied to files:

  • eslint.config.js
  • eslint-rules/corates-ui-imports.js
  • eslint-rules/index.js
📚 Learning: 2026-01-01T23:32:06.095Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/corates.mdc:0-0
Timestamp: 2026-01-01T23:32:06.095Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Use Ark UI components from `corates/ui` package, NOT local components

Applied to files:

  • eslint.config.js
  • eslint-rules/corates-ui-imports.js
  • eslint-rules/index.js
📚 Learning: 2025-12-27T03:02:33.023Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/ui-components.mdc:0-0
Timestamp: 2025-12-27T03:02:33.023Z
Learning: Applies to packages/web/**/*.{js,jsx,ts,tsx} : Use import aliases from jsconfig.json (e.g., @/, components/, auth-ui/, checklist-ui/, project-ui/, routes/, primitives/, api/, config/, lib/) instead of relative paths

Applied to files:

  • eslint.config.js
  • eslint-rules/corates-ui-imports.js
  • eslint-rules/index.js
📚 Learning: 2026-01-01T23:32:06.095Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/corates.mdc:0-0
Timestamp: 2026-01-01T23:32:06.095Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Use import aliases from jsconfig.json (see ui-components.mdc)

Applied to files:

  • eslint.config.js
  • eslint-rules/corates-ui-imports.js
  • eslint-rules/index.js
📚 Learning: 2026-01-06T18:29:08.736Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-06T18:29:08.736Z
Learning: Applies to packages/web/src/**/*.{js,jsx,ts,tsx} : Use import aliases from jsconfig.json (see ui-components.mdc)

Applied to files:

  • eslint.config.js
  • eslint-rules/corates-ui-imports.js
  • eslint-rules/index.js
📚 Learning: 2026-01-06T18:29:08.736Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-06T18:29:08.736Z
Learning: Applies to packages/{web,landing,docs}/src/**/*.{jsx,tsx} : Use Ark UI components from `corates/ui` package, NOT local components

Applied to files:

  • eslint.config.js
  • eslint-rules/corates-ui-imports.js
  • eslint-rules/index.js
📚 Learning: 2026-01-01T23:32:06.095Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/corates.mdc:0-0
Timestamp: 2026-01-01T23:32:06.095Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Prefer modern ES6+ syntax and features

Applied to files:

  • eslint.config.js
📚 Learning: 2026-01-01T23:32:06.095Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/corates.mdc:0-0
Timestamp: 2026-01-01T23:32:06.095Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Use `solid-icons` icon library (e.g., `solid-icons/bi`, `solid-icons/fi`) for icons

Applied to files:

  • eslint.config.js
📚 Learning: 2026-01-01T23:32:06.095Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/corates.mdc:0-0
Timestamp: 2026-01-01T23:32:06.095Z
Learning: Applies to **/*.{js,jsx,ts,tsx,css,scss} : Ensure browser compatibility (Safari is usually problematic)

Applied to files:

  • eslint.config.js
📚 Learning: 2026-01-06T18:29:08.736Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-06T18:29:08.736Z
Learning: Applies to packages/{web,landing,docs}/src/**/*.{jsx,tsx} : Use `solid-icons` for icon imports (e.g., `solid-icons/bi`, `solid-icons/fi`)

Applied to files:

  • eslint.config.js
📚 Learning: 2026-01-06T18:29:08.736Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-06T18:29:08.736Z
Learning: Applies to packages/web/src/**/*.{js,jsx,ts,tsx} : For UI icons, use `solid-icons` library or SVGs only (never emojis)

Applied to files:

  • eslint.config.js
📚 Learning: 2026-01-01T23:32:06.095Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/corates.mdc:0-0
Timestamp: 2026-01-01T23:32:06.095Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : For UI icons, use `solid-icons` library or SVGs only (never emojis)

Applied to files:

  • eslint.config.js
📚 Learning: 2026-01-06T23:56:57.343Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/error-handling.mdc:0-0
Timestamp: 2026-01-06T23:56:57.343Z
Learning: Applies to packages/workers/**/*.{js,ts} : Use predefined error constants from `corates/shared` (PROJECT_ERRORS, AUTH_ERRORS, VALIDATION_ERRORS, SYSTEM_ERRORS, USER_ERRORS) instead of arbitrary error strings

Applied to files:

  • eslint.config.js
  • eslint-rules/index.js
📚 Learning: 2025-12-27T03:01:06.933Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/**,packages/web/src/ROBINS-I/** : Use scoreChecklist utility from @/ROBINS-I/checklist.js to determine risk of bias rating: 'Low' | 'Moderate' | 'Serious' | 'Critical'

Applied to files:

  • packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsx
📚 Learning: 2025-12-27T03:01:06.933Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/**,packages/web/src/AMSTAR2/**,packages/web/src/ROBINS-I/**,packages/web/src/lib/checklist-domain.js,packages/web/src/primitives/useProject/checklists.js : Use checklist operations from useProject hook (createChecklist, updateChecklistAnswer, getChecklistData) instead of manually updating checklist structure

Applied to files:

  • packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsx
📚 Learning: 2025-12-27T03:01:06.933Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/**,packages/web/src/AMSTAR2/** : Use scoreChecklist utility from @/AMSTAR2/checklist.js to determine quality assessment rating: 'High' | 'Moderate' | 'Low' | 'Critically Low'

Applied to files:

  • packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsx
📚 Learning: 2025-12-27T03:02:14.854Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/reconciliation.mdc:0-0
Timestamp: 2025-12-27T03:02:14.854Z
Learning: Applies to {packages/web/src/components/checklist-ui/compare/**,packages/web/src/AMSTAR2/checklist-compare.js} : Use compareChecklists utility from checklist-compare.js for comparing reviewer checklists

Applied to files:

  • packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsx
📚 Learning: 2025-12-27T03:01:06.933Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/**,packages/web/src/ROBINS-I/** : Use shouldStopAssessment utility from @/ROBINS-I/checklist.js to check if Section B indicates critical risk of bias requiring assessment termination

Applied to files:

  • packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsx
📚 Learning: 2025-12-27T03:01:06.933Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/**,packages/web/src/AMSTAR2/**,packages/web/src/ROBINS-I/**,packages/web/src/lib/checklist-domain.js : Use getChecklistStatus utility from @/lib/checklist-domain.js to determine current checklist status before performing operations

Applied to files:

  • packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsx
📚 Learning: 2025-12-27T03:01:06.933Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/**,packages/web/src/AMSTAR2/**,packages/web/src/ROBINS-I/**,packages/web/src/lib/checklist-domain.js : Checklist status transitions follow sequence: in_progress → completed (when all questions answered) → reconciled (after reconciliation complete)

Applied to files:

  • packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsx
📚 Learning: 2025-12-27T03:01:06.933Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/**,packages/web/src/AMSTAR2/**,packages/web/src/ROBINS-I/**,packages/web/src/lib/checklist-domain.js : Maintain separate answer format implementations for each checklist type (AMSTAR2, ROBINS-I, Generic) to prevent data corruption

Applied to files:

  • packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsx
📚 Learning: 2025-12-27T03:02:14.854Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/reconciliation.mdc:0-0
Timestamp: 2025-12-27T03:02:14.854Z
Learning: Applies to {packages/web/src/components/checklist-ui/compare/**,packages/web/src/lib/checklist-domain.js,packages/web/src/AMSTAR2/checklist-compare.js} : Store final answers in the reconciled checklist itself, not in reconciliation progress metadata

Applied to files:

  • packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsx
📚 Learning: 2025-12-27T03:02:14.854Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/reconciliation.mdc:0-0
Timestamp: 2025-12-27T03:02:14.854Z
Learning: Applies to packages/web/src/components/checklist-ui/compare/** : Use Y.Text objects for collaborative editing of question notes in reconciliation

Applied to files:

  • packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsx
📚 Learning: 2025-12-27T03:01:06.933Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/**,packages/web/src/lib/checklist-domain.js : Register and retrieve checklists using checklist-registry: getChecklistType and getChecklistComponent functions

Applied to files:

  • packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsx
📚 Learning: 2025-12-27T03:02:26.947Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx} : Use createSignal for simple reactive values in SolidJS components

Applied to files:

  • packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsx
  • packages/web/src/api/better-auth-store.js
📚 Learning: 2025-12-27T03:02:14.854Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/reconciliation.mdc:0-0
Timestamp: 2025-12-27T03:02:14.854Z
Learning: Applies to {packages/web/src/components/checklist-ui/compare/**,packages/web/src/lib/checklist-domain.js} : Multi-part answers (q9a, q9b, q11a, q11b) should be stored as objects with answer matrix and critical flag properties

Applied to files:

  • packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsx
📚 Learning: 2025-12-27T03:02:26.947Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{jsx,tsx} : Create reusable logic in primitives (hooks) in packages/web/src/primitives/ and import them into components

Applied to files:

  • eslint-rules/corates-ui-imports.js
📚 Learning: 2025-12-27T03:01:35.601Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/durable-objects.mdc:0-0
Timestamp: 2025-12-27T03:01:35.601Z
Learning: Applies to packages/workers/src/durable-objects/**/*.{js,ts} : Track active WebSocket sessions in a Map with session structure { user, awarenessClientId }

Applied to files:

  • packages/web/src/components/settings/pages/SessionManagement.jsx
📚 Learning: 2025-12-27T03:02:26.947Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{jsx,tsx} : Keep SolidJS components lean and focused on rendering - move business logic to stores, primitives, or utilities

Applied to files:

  • packages/web/src/components/settings/pages/SessionManagement.jsx
📚 Learning: 2025-12-27T03:02:26.947Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{jsx,tsx} : Use the children helper when manipulating props.children in SolidJS components

Applied to files:

  • packages/web/src/components/settings/SettingsLayout.jsx
📚 Learning: 2026-01-01T23:31:43.756Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/api-routes.mdc:0-0
Timestamp: 2026-01-01T23:31:43.756Z
Learning: Applies to packages/workers/src/routes/**/*.js : Use error constants from `corates/shared` (`PROJECT_ERRORS.*`, `AUTH_ERRORS.*`, `VALIDATION_ERRORS.*`, `SYSTEM_ERRORS.*`, `USER_ERRORS.*`) instead of creating error objects manually

Applied to files:

  • eslint-rules/index.js
📚 Learning: 2026-01-06T18:29:08.736Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-06T18:29:08.736Z
Learning: Applies to packages/{workers,web}/src/**/*.{js,ts,jsx,tsx} : Use Better-Auth for authentication and user management

Applied to files:

  • packages/web/src/api/better-auth-store.js
📚 Learning: 2025-12-27T03:02:26.947Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx} : Use local createSignal or createStore for local component state; use external stores for shared/cross-feature state

Applied to files:

  • packages/web/src/api/better-auth-store.js
📚 Learning: 2025-12-27T03:01:35.601Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/durable-objects.mdc:0-0
Timestamp: 2025-12-27T03:01:35.601Z
Learning: Applies to packages/workers/src/durable-objects/**/*.{js,ts} : Do not expose internal sync endpoints (/sync, /sync-member, /sync-pdf, /disconnect-all) publicly without X-Internal-Request verification

Applied to files:

  • packages/docs/audits/security-audit-2026-01.md
📚 Learning: 2025-12-27T03:02:05.951Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/pdf-handling.mdc:0-0
Timestamp: 2025-12-27T03:02:05.951Z
Learning: Applies to packages/web/src/**/*.{js,jsx,ts,tsx} : Validate PDF files on frontend by checking file.type includes 'pdf' and file.size is within MAX_PDF_SIZE limit (full validation is done on backend)

Applied to files:

  • packages/docs/audits/security-audit-2026-01.md
📚 Learning: 2025-12-27T03:01:35.601Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/durable-objects.mdc:0-0
Timestamp: 2025-12-27T03:01:35.601Z
Learning: Applies to packages/workers/src/durable-objects/**/ProjectDoc.{js,ts} : Verify authentication before WebSocket upgrade in ProjectDoc

Applied to files:

  • packages/docs/audits/security-audit-2026-01.md
🧬 Code graph analysis (1)
packages/web/src/components/settings/pages/SecuritySettings.jsx (1)
packages/web/src/components/settings/pages/SessionManagement.jsx (1)
  • SessionManagement (165-384)
🪛 LanguageTool
packages/docs/audits/security-audit-2026-01.md

[grammar] ~1032-~1032: Ensure spelling is correct
Context: ...xcept current - revokeSessions() - Logout everywhere 2. Frontend: - Added...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)


[grammar] ~1032-~1032: Ensure spelling is correct
Context: ...- revokeSessions() - Logout everywhere 2. Frontend: - Added session methods t...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Workers Builds: corates
🔇 Additional comments (22)
packages/web/src/components/settings/SettingsLayout.jsx (1)

82-82: LGTM!

The inline children rendering is functionally equivalent to the previous implementation and slightly more concise.

eslint-rules/index.js (1)

1-13: LGTM!

The ESLint plugin entry point follows standard conventions and correctly exports the custom rule for consumption by the ESLint configuration.

packages/web/src/components/settings/pages/SecuritySettings.jsx (3)

3-3: LGTM!

The updated comment accurately reflects the expanded scope of the SecuritySettings component.


7-11: LGTM!

The import changes correctly add the new SessionManagement component and update the icon to FiMonitor, which is semantically appropriate for representing active sessions/devices.


272-284: LGTM!

The Active Sessions section integration follows the established pattern used by other sections in this component. The structure is consistent, and the SessionManagement component is properly integrated.

packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsx (1)

4-4: Import pattern aligns with ESLint rule and requires no changes.

The import import { DialogPrimitive as Dialog } from '@corates/ui' correctly uses the primitive variant with the alias pattern shown in the ESLint rule's own error message template. The rule identifies DialogPrimitive as a primitive component (by the Primitive suffix) and allows it to be imported and aliased. Since the component applies custom styling, using the primitive variant is the correct approach per the rule design.

packages/web/src/api/auth-client.js (1)

49-53: No action required. Better Auth provides all four session management methods (listSessions, revokeSession, revokeOtherSessions, revokeSessions) via authClient on the client side, confirming the implementation is correct.

eslint.config.js (2)

4-4: LGTM! Well-structured ESLint plugin integration.

The custom corates plugin is correctly registered and the corates-ui-imports rule properly enforces the prestyled vs primitive component distinction. This aligns with the project's coding guidelines to import UI components from @corates/ui.

Also applies to: 17-19, 121-125


255-260: Good override for the UI package.

Correctly disables no-restricted-imports for packages/ui/** since the UI package legitimately wraps Ark UI primitives.

packages/web/src/components/settings/pages/SessionManagement.jsx (5)

6-10: Correct import pattern for primitive Dialog usage.

Using DialogPrimitive as Dialog is the correct approach since the component uses primitive patterns (.Root, .Content, .Backdrop, etc.) as required by the new ESLint rule. This follows the @corates/ui component guidelines.


94-163: Well-implemented SessionCard component following SolidJS patterns.

The component correctly:

  • Uses props.session directly without destructuring (SolidJS reactivity)
  • Wraps derived values in functions (deviceInfo = () => ...)
  • Uses Show for conditional rendering
  • Uses solid-icons/fi for icons as per coding guidelines

187-229: Solid deduplication logic with proper current-session handling.

The deduplication correctly prioritizes the current session and keeps the most recent session per device fingerprint. The sorting ensures the current session appears first.


265-280: Intentional asymmetric error handling in handleRevokeAll.

The function correctly does not call setRevokingAll(false) in the success path because the user will be redirected after all sessions are revoked. The state reset only happens in the error path. Good pattern.


352-381: Correct primitive Dialog usage with proper accessibility structure.

The Dialog uses all required primitive subcomponents (.Root, .Backdrop, .Positioner, .Content, .Title, .Description, .CloseTrigger) which aligns with the Ark UI primitive pattern and the new ESLint rule.

packages/web/src/api/better-auth-store.js (2)

33-40: Good import convention with underscore prefix for internal helpers.

Using _listSessions, _revokeSession, etc. for the imported auth-client functions clearly distinguishes them from the public API methods defined in the store. This follows established patterns in the codebase.


872-876: Clean public API extension for session management.

The new methods are properly grouped under a clear comment and follow the existing return object structure.

eslint-rules/corates-ui-imports.js (4)

73-89: Clear and actionable error messages.

The usePrimitive message provides excellent guidance: it names the component, the subcomponent being incorrectly used, and suggests the correct primitive import. This will help developers quickly fix violations.


131-164: Good handling of MemberExpression vs JSXMemberExpression.

Line 134 correctly skips nodes with JSX parent types to avoid duplicate reports, since JSXMemberExpression handles those cases. This prevents the same violation from being reported twice.


198-213: Reasonable decision to disable the "unused primitive" warning.

The commented-out Program:exit check would warn when importing a primitive but not using subcomponent patterns. Keeping this disabled reduces noise since there are legitimate use cases (e.g., passing the primitive to a wrapper component).


11-42: Comprehensive component mapping.

The map correctly covers all Ark UI components that have both prestyled and primitive variants in @corates/ui, including PasswordInput which is properly exported with its primitive version.

packages/docs/audits/security-audit-2026-01.md (2)

1018-1051: Accurate documentation of M1 Session Revocation implementation.

The audit correctly reflects the implementation details:

  • Backend leverages Better Auth's built-in session APIs
  • Frontend additions match the files in this PR (auth-client.js, better-auth-store.js, SessionManagement.jsx, SecuritySettings.jsx)
  • Feature description matches the actual UI implementation

Note: "Logout" (lines 1032) is acceptable American English usage and not a spelling error as flagged by static analysis.


1326-1328: Updated security posture score reflects resolved items.

The score update to 8.8/10 and the narrative change appropriately reflect that short-term security items are resolved.

Comment on lines +1122 to 1155
**Location:** `packages/workers/src/index.js` - `/api/pdf-proxy` endpoint

**Impact:**

- SSRF to internal services (metadata endpoints, databases)
- Port scanning via proxy
- SSRF to localhost (127.0.0.1, ::1)

**Recommendation:**
**Status:** RESOLVED

```javascript
const BLOCKED_IPS = [
'127.0.0.1',
'::1', // Localhost
'169.254.169.254', // AWS metadata
'::ffff:169.254.169.254', // IPv6-mapped AWS metadata
];
**Original Issue:** PDF proxy accepted user-provided URLs without validation, allowing SSRF attacks to internal services.

const BLOCKED_RANGES = [
'10.0.0.0/8', // Private
'172.16.0.0/12', // Private
'192.168.0.0/16', // Private
];
**Implementation:** Added comprehensive SSRF protection with:

async function validateProxyUrl(urlString) {
const url = new URL(urlString);
1. **Blocked hostnames:** `localhost`, `metadata.google.internal`, `metadata.google`
2. **Blocked IP patterns (regex):**
- `127.x.x.x` (loopback)
- `10.x.x.x` (private Class A)
- `172.16-31.x.x` (private Class B)
- `192.168.x.x` (private Class C)
- `169.254.x.x` (link-local / cloud metadata)
- IPv6 loopback, link-local, unique local
3. **Numeric IP blocking:** Blocks decimal IP representations like `2130706433` (127.0.0.1)
4. **Redirect validation:** Also validates redirect destinations to prevent SSRF via open redirects

// Only allow HTTP(S)
if (!['http:', 'https:'].includes(url.protocol)) {
throw new Error('Invalid protocol');
}
**Code:**

// Resolve hostname to IP
const ip = await dns.resolve(url.hostname);
```javascript
// Initial URL validation
if (isBlockedHost(parsedUrl.hostname)) {
console.warn('PDF proxy SSRF attempt blocked:', { hostname: parsedUrl.hostname });
return c.json({ error: 'Access to internal resources is not allowed' }, 403);
}

// Check against blocked IPs/ranges
if (BLOCKED_IPS.includes(ip) || isPrivateIP(ip)) {
throw new Error('Access denied');
}
// Redirect validation
if (isBlockedHost(redirectUrl.hostname)) {
console.warn('PDF proxy SSRF redirect blocked:', { hostname: redirectUrl.hostname });
return c.json({ error: 'Redirect to internal resources is not allowed' }, 403);
}
```
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for isBlockedHost function in the codebase
rg -n 'isBlockedHost' packages/workers/src --type js -A 5 -B 2

Repository: InfinityBowman/corates

Length of output: 48


🏁 Script executed:

#!/bin/bash
# Check if the file mentioned exists
echo "=== Checking if packages/workers/src/index.js exists ==="
ls -la packages/workers/src/index.js 2>&1

echo -e "\n=== Searching for pdf-proxy endpoint ==="
rg -n 'pdf-proxy' packages/workers --type js

echo -e "\n=== Searching for any SSRF blocking logic ==="
rg -n 'blocked.*host|SSRF|internal.*resource' packages/workers --type js -i

echo -e "\n=== Listing packages/workers structure ==="
find packages/workers/src -type f -name "*.js" -o -name "*.ts" | head -20

Repository: InfinityBowman/corates

Length of output: 1603


🏁 Script executed:

#!/bin/bash
# Read the pdf-proxy endpoint implementation
sed -n '219,280p' packages/workers/src/index.js

Repository: InfinityBowman/corates

Length of output: 1922


🏁 Script executed:

#!/bin/bash
# Read more of the pdf-proxy endpoint
sed -n '280,320p' packages/workers/src/index.js

Repository: InfinityBowman/corates

Length of output: 1309


The documented SSRF protections do not exist in the actual implementation. The audit file describes comprehensive protections including hostname blocking (localhost, metadata.google.internal), IP pattern blocking (127.x.x.x, 10.x.x.x, 192.168.x.x, etc.), and an isBlockedHost function—none of which are present in packages/workers/src/index.js.

The actual pdf-proxy endpoint implementation (lines 219–320) contains only basic protocol validation, redirect counting, auth redirect detection, and content-type checking. It lacks all documented SSRF mitigations, leaving the endpoint vulnerable to attacks via private IPs, cloud metadata endpoints, and internal hosts.

Update the audit document to accurately reflect the actual implementation, and either implement the documented protections or remove the false claims of comprehensive SSRF protection.

🤖 Prompt for AI Agents
In @packages/docs/audits/security-audit-2026-01.md around lines 1122 - 1155, The
audit claims a working isBlockedHost-based SSRF defense (blocking hostnames like
"localhost" and "metadata.google.internal", regexes for
127/10/172.16-31/192.168/169.254 and IPv6, numeric-decimal IPs, and redirect
validation) but the pdf-proxy handler actually lacks these checks; either
implement the protections in the pdf-proxy endpoint handler (add an
isBlockedHost(hostname) utility used before fetching and when following
redirects to check parsedUrl.hostname and redirectUrl.hostname, implement
numeric-decimal IP detection/resolution, the listed regex/IP ranges and explicit
blocked hostnames, and ensure redirect validation increments redirect count and
rechecks targets) or update the audit doc to remove the false claims and
document the real current behavior (keep references to isBlockedHost,
parsedUrl.hostname, redirectUrl.hostname and the pdf-proxy handler to locate
where to add or remove the described protections).

Comment on lines +676 to +687
async function revokeAllSessions() {
try {
await _revokeSessions();
// Clear local state after revoking all sessions
saveCachedAuth(null);
setCachedUser(null);
setCachedAvatarUrl(null);
} catch (err) {
setAuthError(err.message);
throw err;
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Consider mirroring full signout cleanup in revokeAllSessions.

When revoking all sessions (including current), the user is effectively logged out. However, unlike signout() (lines 432-466), this function doesn't:

  • Clear the avatar cache from IndexedDB (clearAvatarCache())
  • Clear the query cache (queryClient.clear())
  • Clear persisted query cache (clearPersistedQueryCache())
  • Refetch session to immediately clear state

This could leave stale data in caches if the user logs back in as a different user.

🔎 Proposed fix
   async function revokeAllSessions() {
     try {
       await _revokeSessions();
       // Clear local state after revoking all sessions
       saveCachedAuth(null);
       setCachedUser(null);
       setCachedAvatarUrl(null);
+      
+      // Mirror signout() cleanup for full cache clearing
+      clearAvatarCache();
+      queryClient.clear();
+      await clearPersistedQueryCache();
     } catch (err) {
       setAuthError(err.message);
       throw err;
     }
   }
🤖 Prompt for AI Agents
In @packages/web/src/api/better-auth-store.js around lines 676 - 687, The
revokeAllSessions function currently calls _revokeSessions and clears local
in-memory state (saveCachedAuth, setCachedUser, setCachedAvatarUrl) but does not
perform the full signout cleanup; update revokeAllSessions to mirror signout():
after successful _revokeSessions() call invoke clearAvatarCache(), call
queryClient.clear(), call clearPersistedQueryCache(), trigger a refetch of the
session (e.g., refetchSession()) to immediately reset state, and then clear
in-memory caches and avatar like existing saveCachedAuth(null),
setCachedUser(null), setCachedAvatarUrl(null); keep the existing error handling
that sets setAuthError(err.message) and rethrows from the catch that references
_revokeSessions.

@InfinityBowman InfinityBowman merged commit 41844f2 into main Jan 7, 2026
3 checks passed
@InfinityBowman InfinityBowman deleted the 159-auth---user-active-sessions branch January 7, 2026 07:50
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.

Auth - User active sessions

2 participants