Skip to content

Staging#63

Closed
AustinKelsay wants to merge 378 commits intomainfrom
staging
Closed

Staging#63
AustinKelsay wants to merge 378 commits intomainfrom
staging

Conversation

@AustinKelsay
Copy link
Copy Markdown
Member

@AustinKelsay AustinKelsay commented Jan 6, 2026

Summary by CodeRabbit

  • New Features

    • Import shares from other devices; Group/Share QR codes; smarter relay planning available to the UI.
  • Bug Fixes

    • Prevented stale state updates on unmount/navigation; sanitized user-facing errors; masked and auto-cleared recovered secret material; improved input validation UX.
  • Security

    • Hardened IPC/preload surface, stricter CSP and navigation controls, file-permission hardening, SSRF protections, and centralized runtime validation/limits.
  • Tests

    • Expanded coverage for validation, relay planning, IPC schemas, echo/listener flows, and UI edge cases.

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

AustinKelsay and others added 30 commits May 6, 2025 09:12
…with different screens, adding consistency to elements and consolidating as many as possible first round
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
…e, and consistent button alignment. Enhance QR modal with better status feedback and fix 'Try Again' loading state.
Copy link
Copy Markdown
Contributor

@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 @src/components/AddShare.tsx:
- Around line 395-415: The IPC call to window.electronAPI.computeRelayPlan is
passing explicitRelays: null and envRelay: null which will fail
RelayPlanArgsSchema validation because the schema uses .optional() (accepts
undefined/omission, not null); change the AddShare.tsx call to pass undefined
(or omit the keys) for explicitRelays and envRelay so the payload conforms to
RelayPlanArgsSchema, or alternatively update RelayPlanArgsSchema to use
.nullable()/.nullish() if you intend to accept nulls—prefer the AddShare.tsx
change to undefined to minimize schema changes.

In @src/main.ts:
- Around line 116-127: The unquoted Unix path regex in function
sanitizeErrorForLog incorrectly excludes spaces; update the pattern used in
sanitizeErrorForLog from /\/(?:[^\/\s:]+\/)+([^\/\s:]+)/g to a pattern that
allows spaces in path segments (for example /\/(?:[^\/\s]+\/)+([^\/\s]+)/g) so
that "/path/with spaces/file.txt" is fully replaced to "<path>/file.txt"; after
changing the regex, run and add unit tests exercising sanitizeErrorForLog with
unquoted Unix paths that include spaces to verify the behavior.
🧹 Nitpick comments (9)
index.html (1)

5-27: Strong CSP implementation with well-documented trade-offs.

The Content-Security-Policy provides robust protection for an Electron application:

Strong protections:

  • script-src 'self' blocks inline scripts and eval
  • object-src 'none' prevents plugin execution
  • frame-ancestors 'none' prevents clickjacking
  • Blocks insecure ws:// connections

Necessary allowances (well-documented):

  • style-src 'unsafe-inline' required for Tailwind CSS (lower risk than script injection)
  • connect-src wss: wildcard required for user-configured nostr relays (intentionally blocks non-TLS ws://)

The comments clearly explain the rationale for each allowance, making the security trade-offs transparent.

Optional future hardening: If relay URLs become available at initialization time, consider implementing a dynamic CSP or validating relay URLs to further restrict the wss: wildcard.

src/__tests__/integration/computeRelayPlan.test.ts (1)

14-68: Useful static analysis tests for IPC contract verification.

The static analysis approach verifies the IPC handler structure without executing it, providing early detection of:

  • Missing handler registration
  • Schema definition changes
  • Env var fallback logic
  • Input normalization patterns

However, these tests may be brittle to code refactoring (e.g., variable renaming, code reorganization) while the actual behavior remains correct.

Consider complementing static analysis with a unit test for the actual computeRelayPlan logic in echoRelays.ts to ensure the behavior is tested independently of code structure.

src/__tests__/components/Recover.test.tsx (1)

426-435: Consider making masked character count assertion more flexible.

The assertion expect(screen.getByText(/•{40}/)) assumes exactly 40 masking characters. If the NSEC length varies or the masking logic changes, this test will fail. Consider a more flexible pattern like /•{10,}/ or deriving the expected count from the NSEC length.

♻️ Suggested change
-      expect(screen.getByText(/•{40}/)).toBeInTheDocument();
+      // Verify masking dots are present (flexible count)
+      expect(screen.getByText(/•{10,}/)).toBeInTheDocument();
src/main.ts (2)

267-288: Consider extracting URL canonicalization to a shared utility.

The relayTargetKey function duplicates logic from dedupeKey in src/lib/echoRelays.ts. Consider importing and reusing the shared implementation for consistency.


496-565: Consider adding timeout for echo listener startup.

The startEchoMonitor call could hang if relay connections stall. Consider wrapping with a timeout to prevent indefinite blocking.

♻️ Suggested timeout wrapper
+const ECHO_START_TIMEOUT_MS = 30000;
+
 try {
-  const listener = await startEchoMonitor(groupCredential, normalizedShares, (shareIndex, shareCredential, challenge) => {
+  const listenerPromise = startEchoMonitor(groupCredential, normalizedShares, (shareIndex, shareCredential, challenge) => {
     if (!event.sender.isDestroyed()) {
       event.sender.send('echo-received', {
         listenerId,
         shareIndex,
         shareCredential,
         challenge: challenge ?? null,
       });
     }
   });
+
+  const timeoutPromise = new Promise<never>((_, reject) =>
+    setTimeout(() => reject(new Error('Echo listener startup timed out')), ECHO_START_TIMEOUT_MS)
+  );
+
+  const listener = await Promise.race([listenerPromise, timeoutPromise]);
src/components/AddShare.tsx (1)

125-154: Good validation with centralized limits, but consider using validateShareName utility.

The evaluateShareName function implements name validation inline. The codebase now has validateShareName in src/lib/validation.ts that provides similar functionality with normalization. Consider using the shared utility for consistency.

src/__tests__/integration/electron-security.test.ts (1)

82-86: Regex may be overly strict for ipcRenderer exposure check.

The pattern exposeInMainWorld\([^)]*ipcRenderer[^)]*\) checks for raw ipcRenderer exposure but may not catch all patterns. Consider also checking for patterns like ipcRenderer.send or ipcRenderer.invoke being directly exposed.

src/lib/validation.ts (1)

127-153: Comprehensive SSRF protection for private IP ranges.

The function correctly blocks:

  • RFC 1918 private ranges (10.x, 172.16-31.x, 192.168.x)
  • Loopback (127.x)
  • Link-local (169.254.x)
  • Reserved (0.x)

Consider also blocking:

  • Broadcast (255.255.255.255)
  • Multicast (224.0.0.0 - 239.255.255.255)
♻️ Extended SSRF protection
   // Reserved
   if (parts[0] === 0) return true;                                       // 0.0.0.0/8

+  // Broadcast
+  if (parts[0] === 255 && parts[1] === 255 && parts[2] === 255 && parts[3] === 255) return true;
+
+  // Multicast (Class D)
+  if (parts[0] >= 224 && parts[0] <= 239) return true;                   // 224.0.0.0/4
+
   return false;
src/components/Recover.tsx (1)

758-805: Inconsistent indentation in button layout.

The nested button elements have inconsistent indentation which affects readability. The second and third buttons inside the flex gap-2 container should align with the first button.

🔧 Suggested fix for indentation
             <div className="flex gap-2">
               <Button
                 type="button"
                 onClick={handleCopyNsec}
                 className={`flex-1 text-sm ${copyError ? 'bg-red-600 hover:bg-red-700' : 'bg-blue-600 hover:bg-blue-700'}`}
               >
                 {isNsecCopied ? (
                   <>
                     <Check className="w-4 h-4 mr-2" />
                     Copied!
                   </>
                 ) : (
                   <>
                     <Copy className="w-4 h-4 mr-2" />
                     Copy to Clipboard
                   </>
                 )}
               </Button>

-              <Button
-                type="button"
-                onClick={handleToggleNsecReveal}
-                variant="outline"
-                className="bg-gray-700 hover:bg-gray-600 border-gray-600 text-sm"
-              >
-                {isNsecRevealed ? (
-                  <>
-                    <EyeOff className="w-4 h-4 mr-2" />
-                    Hide
-                  </>
-                ) : (
-                  <>
-                    <Eye className="w-4 h-4 mr-2" />
-                    Reveal
-                  </>
-                )}
-              </Button>
-
-              <Button
-                type="button"
-                onClick={clearRecoveredNsec}
-                variant="outline"
-                className="bg-red-900/30 hover:bg-red-800/50 border-red-700/50 text-red-300 text-sm"
-              >
-                Clear
-              </Button>
+               <Button
+                 type="button"
+                 onClick={handleToggleNsecReveal}
+                 variant="outline"
+                 className="bg-gray-700 hover:bg-gray-600 border-gray-600 text-sm"
+               >
+                 {isNsecRevealed ? (
+                   <>
+                     <EyeOff className="w-4 h-4 mr-2" />
+                     Hide
+                   </>
+                 ) : (
+                   <>
+                     <Eye className="w-4 h-4 mr-2" />
+                     Reveal
+                   </>
+                 )}
+               </Button>
+
+               <Button
+                 type="button"
+                 onClick={clearRecoveredNsec}
+                 variant="outline"
+                 className="bg-red-900/30 hover:bg-red-800/50 border-red-700/50 text-red-300 text-sm"
+               >
+                 Clear
+               </Button>
             </div>
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1bb4086 and 7fc4b3d.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (37)
  • CLAUDE.md
  • SECURITY_AUDIT_2026-01-06.md
  • index.html
  • package.json
  • src/__tests__/__mocks__/bifrost.mock.ts
  • src/__tests__/components/AddShare.test.tsx
  • src/__tests__/components/LoadShare.test.tsx
  • src/__tests__/components/Recover.test.tsx
  • src/__tests__/components/SaveShare.test.tsx
  • src/__tests__/components/Signer.test.tsx
  • src/__tests__/integration/clientShareManager.test.ts
  • src/__tests__/integration/computeRelayPlan.test.ts
  • src/__tests__/integration/electron-security.test.ts
  • src/__tests__/integration/userInputValidation.test.ts
  • src/__tests__/lib/echoRelays.test.ts
  • src/__tests__/lib/igloo-core-integration.test.ts
  • src/__tests__/lib/shareManager.test.ts
  • src/__tests__/lib/validation.test.ts
  • src/__tests__/setup.ts
  • src/__tests__/workflows/keyset-creation.test.ts
  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/components/AddShare.tsx
  • src/components/Create.tsx
  • src/components/Keyset.tsx
  • src/components/LoadShare.tsx
  • src/components/Recover.tsx
  • src/components/SaveShare.tsx
  • src/components/Signer.tsx
  • src/lib/clientShareManager.ts
  • src/lib/echoRelays.ts
  • src/lib/shareManager.ts
  • src/lib/validation.ts
  • src/main.ts
  • src/preload.ts
  • tsconfig.preload.json
  • tsconfig.test.json
  • webpack.config.cjs
🧰 Additional context used
📓 Path-based instructions (17)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Use strict TypeScript mode with explicit types for function parameters and returns
Prefer interfaces over types for defining object shapes in TypeScript
Use @/ path alias for imports instead of relative paths
Use camelCase for functions and variables
Use UPPER_SNAKE_CASE for constants

Files:

  • src/lib/clientShareManager.ts
  • src/lib/shareManager.ts
  • src/__tests__/components/AddShare.test.tsx
  • src/components/Signer.tsx
  • src/lib/echoRelays.ts
  • src/__tests__/lib/shareManager.test.ts
  • src/__tests__/integration/userInputValidation.test.ts
  • src/__tests__/components/Recover.test.tsx
  • src/__tests__/components/LoadShare.test.tsx
  • src/components/Create.tsx
  • src/__tests__/__mocks__/bifrost.mock.ts
  • src/__tests__/integration/clientShareManager.test.ts
  • src/components/AddShare.tsx
  • src/__tests__/integration/computeRelayPlan.test.ts
  • src/preload.ts
  • src/main.ts
  • src/__tests__/components/SaveShare.test.tsx
  • src/__tests__/integration/electron-security.test.ts
  • src/components/Keyset.tsx
  • src/__tests__/lib/igloo-core-integration.test.ts
  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/components/LoadShare.tsx
  • src/__tests__/workflows/keyset-creation.test.ts
  • src/__tests__/lib/echoRelays.test.ts
  • src/components/SaveShare.tsx
  • src/__tests__/components/Signer.test.tsx
  • src/components/Recover.tsx
  • src/__tests__/setup.ts
  • src/__tests__/lib/validation.test.ts
  • src/lib/validation.ts
src/{components,lib,types}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

UI components sit under src/components/, helpers in src/lib/, shared types in src/types/

Files:

  • src/lib/clientShareManager.ts
  • src/lib/shareManager.ts
  • src/components/Signer.tsx
  • src/lib/echoRelays.ts
  • src/components/Create.tsx
  • src/components/AddShare.tsx
  • src/components/Keyset.tsx
  • src/components/LoadShare.tsx
  • src/components/SaveShare.tsx
  • src/components/Recover.tsx
  • src/lib/validation.ts
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.{ts,tsx}: All runtime code is TypeScript with two-space indentation and required semicolons
Import third-party packages before internal modules and use the @/ alias for local paths

Files:

  • src/lib/clientShareManager.ts
  • src/lib/shareManager.ts
  • src/__tests__/components/AddShare.test.tsx
  • src/components/Signer.tsx
  • src/lib/echoRelays.ts
  • src/__tests__/lib/shareManager.test.ts
  • src/__tests__/integration/userInputValidation.test.ts
  • src/__tests__/components/Recover.test.tsx
  • src/__tests__/components/LoadShare.test.tsx
  • src/components/Create.tsx
  • src/__tests__/__mocks__/bifrost.mock.ts
  • src/__tests__/integration/clientShareManager.test.ts
  • src/components/AddShare.tsx
  • src/__tests__/integration/computeRelayPlan.test.ts
  • src/preload.ts
  • src/main.ts
  • src/__tests__/components/SaveShare.test.tsx
  • src/__tests__/integration/electron-security.test.ts
  • src/components/Keyset.tsx
  • src/__tests__/lib/igloo-core-integration.test.ts
  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/components/LoadShare.tsx
  • src/__tests__/workflows/keyset-creation.test.ts
  • src/__tests__/lib/echoRelays.test.ts
  • src/components/SaveShare.tsx
  • src/__tests__/components/Signer.test.tsx
  • src/components/Recover.tsx
  • src/__tests__/setup.ts
  • src/__tests__/lib/validation.test.ts
  • src/lib/validation.ts
src/lib/shareManager.ts

📄 CodeRabbit inference engine (CLAUDE.md)

src/lib/shareManager.ts: Never store plaintext share data; always encrypt with user passwords
Store shares in /igloo/shares/ directory using the defined JSON schema

Files:

  • src/lib/shareManager.ts
src/__tests__/**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

src/__tests__/**/*.test.{ts,tsx}: Mock @frostr/igloo-core functions at the module level in tests to avoid ESM/Jest complications
Use jest.clearAllMocks() in beforeEach hooks to ensure test isolation
Mock Electron's ipcRenderer and app APIs in tests

Files:

  • src/__tests__/components/AddShare.test.tsx
  • src/__tests__/lib/shareManager.test.ts
  • src/__tests__/integration/userInputValidation.test.ts
  • src/__tests__/components/Recover.test.tsx
  • src/__tests__/components/LoadShare.test.tsx
  • src/__tests__/integration/clientShareManager.test.ts
  • src/__tests__/integration/computeRelayPlan.test.ts
  • src/__tests__/components/SaveShare.test.tsx
  • src/__tests__/integration/electron-security.test.ts
  • src/__tests__/lib/igloo-core-integration.test.ts
  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/__tests__/workflows/keyset-creation.test.ts
  • src/__tests__/lib/echoRelays.test.ts
  • src/__tests__/components/Signer.test.tsx
  • src/__tests__/lib/validation.test.ts
src/__tests__/components/**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Test React component behavior in tests/components/ directory

Files:

  • src/__tests__/components/AddShare.test.tsx
  • src/__tests__/components/Recover.test.tsx
  • src/__tests__/components/LoadShare.test.tsx
  • src/__tests__/components/SaveShare.test.tsx
  • src/__tests__/components/Signer.test.tsx
src/__tests__/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Tests mirror runtime code under src/__tests__/ with integration/, performance/, and __mocks__/ subdirectories for feature-specific coverage

Files:

  • src/__tests__/components/AddShare.test.tsx
  • src/__tests__/lib/shareManager.test.ts
  • src/__tests__/integration/userInputValidation.test.ts
  • src/__tests__/components/Recover.test.tsx
  • src/__tests__/components/LoadShare.test.tsx
  • src/__tests__/__mocks__/bifrost.mock.ts
  • src/__tests__/integration/clientShareManager.test.ts
  • src/__tests__/integration/computeRelayPlan.test.ts
  • src/__tests__/components/SaveShare.test.tsx
  • src/__tests__/integration/electron-security.test.ts
  • src/__tests__/lib/igloo-core-integration.test.ts
  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/__tests__/workflows/keyset-creation.test.ts
  • src/__tests__/lib/echoRelays.test.ts
  • src/__tests__/components/Signer.test.tsx
  • src/__tests__/setup.ts
  • src/__tests__/lib/validation.test.ts
src/**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Jest with Testing Library powers renderer specs; place new tests beside features as <subject>.test.tsx

Files:

  • src/__tests__/components/AddShare.test.tsx
  • src/__tests__/lib/shareManager.test.ts
  • src/__tests__/integration/userInputValidation.test.ts
  • src/__tests__/components/Recover.test.tsx
  • src/__tests__/components/LoadShare.test.tsx
  • src/__tests__/integration/clientShareManager.test.ts
  • src/__tests__/integration/computeRelayPlan.test.ts
  • src/__tests__/components/SaveShare.test.tsx
  • src/__tests__/integration/electron-security.test.ts
  • src/__tests__/lib/igloo-core-integration.test.ts
  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/__tests__/workflows/keyset-creation.test.ts
  • src/__tests__/lib/echoRelays.test.ts
  • src/__tests__/components/Signer.test.tsx
  • src/__tests__/lib/validation.test.ts
src/components/[A-Z]*.tsx

📄 CodeRabbit inference engine (CLAUDE.md)

Use PascalCase for component files

Files:

  • src/components/Signer.tsx
  • src/components/Create.tsx
  • src/components/AddShare.tsx
  • src/components/Keyset.tsx
  • src/components/LoadShare.tsx
  • src/components/SaveShare.tsx
  • src/components/Recover.tsx
src/components/**/*.tsx

📄 CodeRabbit inference engine (CLAUDE.md)

src/components/**/*.tsx: Use Tailwind CSS utility classes in JSX and use cn() utility for conditional classes
Avoid inline styles unless conditionally computed
Use functional components with hooks instead of class components
Use ipcRenderer.invoke() in renderer process to call IPC handlers without direct file system access

Tailwind utility classes style JSX; reserve inline styles for dynamic values only

Files:

  • src/components/Signer.tsx
  • src/components/Create.tsx
  • src/components/AddShare.tsx
  • src/components/Keyset.tsx
  • src/components/LoadShare.tsx
  • src/components/SaveShare.tsx
  • src/components/Recover.tsx
src/components/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

src/components/**/*.{ts,tsx}: Prefer functional React components; name them in PascalCase and helpers in camelCase
Components in src/components/ follow kebab-case filenames (e.g., share-list.tsx)

Files:

  • src/components/Signer.tsx
  • src/components/Create.tsx
  • src/components/AddShare.tsx
  • src/components/Keyset.tsx
  • src/components/LoadShare.tsx
  • src/components/SaveShare.tsx
  • src/components/Recover.tsx
src/__tests__/lib/**/*.test.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Test utility functions in tests/lib/ directory

Files:

  • src/__tests__/lib/shareManager.test.ts
  • src/__tests__/lib/igloo-core-integration.test.ts
  • src/__tests__/lib/echoRelays.test.ts
  • src/__tests__/lib/validation.test.ts
src/__tests__/integration/**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Test Electron IPC communication in tests/integration/ directory

Files:

  • src/__tests__/integration/userInputValidation.test.ts
  • src/__tests__/integration/clientShareManager.test.ts
  • src/__tests__/integration/computeRelayPlan.test.ts
  • src/__tests__/integration/electron-security.test.ts
src/__tests__/__mocks__/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Place shared mock implementations in tests/mocks/ for use across test files

Files:

  • src/__tests__/__mocks__/bifrost.mock.ts
src/__tests__/{setup.ts,__mocks__/**}

📄 CodeRabbit inference engine (AGENTS.md)

Register shared mocks in src/__tests__/setup.ts and reuse fixtures from src/__tests__/__mocks__/

Files:

  • src/__tests__/__mocks__/bifrost.mock.ts
  • src/__tests__/setup.ts
src/main.ts

📄 CodeRabbit inference engine (CLAUDE.md)

src/main.ts: Register IPC handlers in main.ts using ipcMain.handle() for file system operations
Electron's main process uses CommonJS (require) while renderer uses ESM (import)

Main Electron process lives in src/main.ts; the renderer bootstraps from src/renderer.tsx

Files:

  • src/main.ts
src/__tests__/workflows/**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Test end-to-end user flows in tests/workflows/ directory

Files:

  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/__tests__/workflows/keyset-creation.test.ts
🧠 Learnings (28)
📓 Common learnings
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T23:50:29.859Z
Learning: Applies to src/**/*ipc*.{ts,tsx} : Cover new IPC handlers with unit tests plus at least one scenario in `src/__tests__/integration/`
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/__tests__/integration/**/*.test.{ts,tsx} : Test Electron IPC communication in __tests__/integration/ directory
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/lib/shareManager.ts : Store shares in <appData>/igloo/shares/ directory using the defined JSON schema

Applied to files:

  • src/lib/clientShareManager.ts
  • src/lib/shareManager.ts
  • src/__tests__/lib/shareManager.test.ts
  • src/__tests__/integration/clientShareManager.test.ts
  • src/components/AddShare.tsx
  • src/main.ts
  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/components/Recover.tsx
  • CLAUDE.md
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/__tests__/integration/**/*.test.{ts,tsx} : Test Electron IPC communication in __tests__/integration/ directory

Applied to files:

  • src/lib/clientShareManager.ts
  • src/__tests__/components/AddShare.test.tsx
  • src/__tests__/lib/shareManager.test.ts
  • src/__tests__/integration/userInputValidation.test.ts
  • src/__tests__/components/Recover.test.tsx
  • src/__tests__/components/LoadShare.test.tsx
  • src/__tests__/integration/clientShareManager.test.ts
  • src/__tests__/integration/computeRelayPlan.test.ts
  • src/preload.ts
  • src/main.ts
  • src/__tests__/components/SaveShare.test.tsx
  • src/__tests__/integration/electron-security.test.ts
  • src/__tests__/lib/igloo-core-integration.test.ts
  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/__tests__/lib/echoRelays.test.ts
  • src/__tests__/setup.ts
  • src/__tests__/lib/validation.test.ts
  • CLAUDE.md
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/lib/shareManager.ts : Never store plaintext share data; always encrypt with user passwords

Applied to files:

  • src/lib/clientShareManager.ts
  • src/lib/shareManager.ts
  • src/__tests__/components/AddShare.test.tsx
  • src/__tests__/lib/shareManager.test.ts
  • src/__tests__/components/LoadShare.test.tsx
  • src/__tests__/__mocks__/bifrost.mock.ts
  • src/__tests__/integration/clientShareManager.test.ts
  • src/components/AddShare.tsx
  • src/__tests__/components/SaveShare.test.tsx
  • src/components/Keyset.tsx
  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/components/LoadShare.tsx
  • src/__tests__/workflows/keyset-creation.test.ts
  • src/components/SaveShare.tsx
  • src/components/Recover.tsx
  • CLAUDE.md
  • SECURITY_AUDIT_2026-01-06.md
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/main.ts : Register IPC handlers in main.ts using ipcMain.handle() for file system operations

Applied to files:

  • src/lib/clientShareManager.ts
  • src/__tests__/integration/computeRelayPlan.test.ts
  • src/preload.ts
  • src/main.ts
  • src/__tests__/integration/electron-security.test.ts
  • src/components/Keyset.tsx
📚 Learning: 2026-01-02T23:50:29.859Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T23:50:29.859Z
Learning: Applies to src/**/*ipc*.{ts,tsx} : Cover new IPC handlers with unit tests plus at least one scenario in `src/__tests__/integration/`

Applied to files:

  • src/lib/clientShareManager.ts
  • src/__tests__/components/AddShare.test.tsx
  • src/__tests__/lib/shareManager.test.ts
  • src/__tests__/integration/userInputValidation.test.ts
  • src/__tests__/components/Recover.test.tsx
  • src/__tests__/components/LoadShare.test.tsx
  • src/__tests__/integration/clientShareManager.test.ts
  • src/__tests__/integration/computeRelayPlan.test.ts
  • src/main.ts
  • src/__tests__/components/SaveShare.test.tsx
  • src/__tests__/integration/electron-security.test.ts
  • src/__tests__/lib/igloo-core-integration.test.ts
  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/__tests__/lib/echoRelays.test.ts
  • src/__tests__/components/Signer.test.tsx
  • src/__tests__/setup.ts
  • src/__tests__/lib/validation.test.ts
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/components/**/*.tsx : Use ipcRenderer.invoke() in renderer process to call IPC handlers without direct file system access

Applied to files:

  • src/lib/clientShareManager.ts
  • src/__tests__/integration/clientShareManager.test.ts
  • src/__tests__/integration/computeRelayPlan.test.ts
  • src/preload.ts
  • src/main.ts
  • src/__tests__/integration/electron-security.test.ts
  • src/components/Keyset.tsx
  • src/__tests__/setup.ts
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/__tests__/**/*.test.{ts,tsx} : Mock Electron's ipcRenderer and app APIs in tests

Applied to files:

  • src/__tests__/components/AddShare.test.tsx
  • src/__tests__/components/Recover.test.tsx
  • src/__tests__/integration/clientShareManager.test.ts
  • src/__tests__/integration/computeRelayPlan.test.ts
  • src/preload.ts
  • src/main.ts
  • src/__tests__/integration/electron-security.test.ts
  • src/__tests__/workflows/share-lifecycle.test.ts
  • webpack.config.cjs
  • src/__tests__/components/Signer.test.tsx
  • src/__tests__/setup.ts
📚 Learning: 2026-01-02T23:50:29.859Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T23:50:29.859Z
Learning: Applies to src/__tests__/{setup.ts,__mocks__/**} : Register shared mocks in `src/__tests__/setup.ts` and reuse fixtures from `src/__tests__/__mocks__/`

Applied to files:

  • src/__tests__/components/AddShare.test.tsx
  • src/__tests__/components/Recover.test.tsx
  • src/__tests__/__mocks__/bifrost.mock.ts
  • src/__tests__/integration/clientShareManager.test.ts
  • src/__tests__/components/SaveShare.test.tsx
  • src/__tests__/lib/igloo-core-integration.test.ts
  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/__tests__/workflows/keyset-creation.test.ts
  • src/__tests__/components/Signer.test.tsx
  • src/__tests__/setup.ts
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/__tests__/__mocks__/**/*.ts : Place shared mock implementations in __tests__/__mocks__/ for use across test files

Applied to files:

  • src/__tests__/components/AddShare.test.tsx
  • src/__tests__/lib/shareManager.test.ts
  • src/__tests__/__mocks__/bifrost.mock.ts
  • src/__tests__/integration/clientShareManager.test.ts
  • src/__tests__/components/SaveShare.test.tsx
  • tsconfig.test.json
  • src/__tests__/lib/igloo-core-integration.test.ts
  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/__tests__/workflows/keyset-creation.test.ts
  • src/__tests__/setup.ts
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/__tests__/**/*.test.{ts,tsx} : Mock frostr/igloo-core functions at the module level in tests to avoid ESM/Jest complications

Applied to files:

  • src/__tests__/components/AddShare.test.tsx
  • src/__tests__/lib/shareManager.test.ts
  • src/__tests__/components/Recover.test.tsx
  • src/__tests__/__mocks__/bifrost.mock.ts
  • src/__tests__/integration/clientShareManager.test.ts
  • tsconfig.test.json
  • src/__tests__/lib/igloo-core-integration.test.ts
  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/__tests__/workflows/keyset-creation.test.ts
  • src/__tests__/lib/echoRelays.test.ts
  • src/__tests__/components/Signer.test.tsx
  • src/__tests__/setup.ts
  • package.json
📚 Learning: 2026-01-02T23:50:29.859Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T23:50:29.859Z
Learning: Applies to src/__tests__/**/*.{ts,tsx} : Tests mirror runtime code under `src/__tests__/` with `integration/`, `performance/`, and `__mocks__/` subdirectories for feature-specific coverage

Applied to files:

  • src/__tests__/components/AddShare.test.tsx
  • src/__tests__/lib/shareManager.test.ts
  • src/__tests__/components/Recover.test.tsx
  • src/__tests__/components/LoadShare.test.tsx
  • src/__tests__/integration/clientShareManager.test.ts
  • src/__tests__/integration/computeRelayPlan.test.ts
  • src/__tests__/components/SaveShare.test.tsx
  • src/__tests__/integration/electron-security.test.ts
  • tsconfig.test.json
  • src/__tests__/lib/igloo-core-integration.test.ts
  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/__tests__/lib/echoRelays.test.ts
  • src/__tests__/components/Signer.test.tsx
  • src/__tests__/setup.ts
  • src/__tests__/lib/validation.test.ts
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/__tests__/**/*.test.{ts,tsx} : Use jest.clearAllMocks() in beforeEach hooks to ensure test isolation

Applied to files:

  • src/__tests__/components/AddShare.test.tsx
  • src/__tests__/components/Recover.test.tsx
  • src/__tests__/integration/clientShareManager.test.ts
  • tsconfig.test.json
  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/__tests__/workflows/keyset-creation.test.ts
  • src/__tests__/components/Signer.test.tsx
  • src/__tests__/setup.ts
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/__tests__/components/**/*.test.{ts,tsx} : Test React component behavior in __tests__/components/ directory

Applied to files:

  • src/__tests__/components/AddShare.test.tsx
  • src/__tests__/components/Recover.test.tsx
  • src/__tests__/components/LoadShare.test.tsx
  • src/__tests__/components/SaveShare.test.tsx
  • src/__tests__/integration/electron-security.test.ts
  • tsconfig.test.json
  • src/__tests__/lib/validation.test.ts
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/__tests__/lib/**/*.test.ts : Test utility functions in __tests__/lib/ directory

Applied to files:

  • src/__tests__/components/AddShare.test.tsx
  • src/__tests__/lib/shareManager.test.ts
  • src/__tests__/components/Recover.test.tsx
  • src/__tests__/components/LoadShare.test.tsx
  • src/__tests__/integration/computeRelayPlan.test.ts
  • src/__tests__/components/SaveShare.test.tsx
  • src/__tests__/integration/electron-security.test.ts
  • tsconfig.test.json
  • src/__tests__/lib/igloo-core-integration.test.ts
  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/__tests__/lib/echoRelays.test.ts
  • src/__tests__/lib/validation.test.ts
  • CLAUDE.md
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Do not implement cryptographic logic in the desktop app; delegate all crypto operations to frostr/igloo-core

Applied to files:

  • src/components/Signer.tsx
  • src/components/AddShare.tsx
  • CLAUDE.md
📚 Learning: 2026-01-02T23:50:29.859Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T23:50:29.859Z
Learning: Applies to src/**/*.test.{ts,tsx} : Jest with Testing Library powers renderer specs; place new tests beside features as `<subject>.test.tsx`

Applied to files:

  • src/__tests__/components/Recover.test.tsx
  • src/__tests__/integration/electron-security.test.ts
  • tsconfig.test.json
  • src/__tests__/components/Signer.test.tsx
  • src/__tests__/setup.ts
  • src/__tests__/lib/validation.test.ts
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/lib/encryption.ts : Use PBKDF2 with 600,000 iterations for encrypting share files

Applied to files:

  • src/__tests__/__mocks__/bifrost.mock.ts
  • src/components/LoadShare.tsx
  • src/components/SaveShare.tsx
📚 Learning: 2026-01-02T23:50:29.859Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T23:50:29.859Z
Learning: Applies to src/**/*.{ts,tsx} : Import third-party packages before internal modules and use the `@/` alias for local paths

Applied to files:

  • tsconfig.preload.json
  • tsconfig.test.json
  • webpack.config.cjs
  • CLAUDE.md
📚 Learning: 2026-01-02T23:50:29.859Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T23:50:29.859Z
Learning: Applies to src/**/*.{ts,tsx} : All runtime code is TypeScript with two-space indentation and required semicolons

Applied to files:

  • tsconfig.preload.json
  • tsconfig.test.json
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/main.ts : Electron's main process uses CommonJS (require) while renderer uses ESM (import)

Applied to files:

  • src/preload.ts
  • src/main.ts
  • src/__tests__/integration/electron-security.test.ts
  • webpack.config.cjs
  • src/__tests__/setup.ts
  • CLAUDE.md
  • package.json
📚 Learning: 2026-01-02T23:50:29.859Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T23:50:29.859Z
Learning: Applies to src/main.ts : Main Electron process lives in `src/main.ts`; the renderer bootstraps from `src/renderer.tsx`

Applied to files:

  • src/preload.ts
  • src/__tests__/integration/electron-security.test.ts
  • webpack.config.cjs
  • CLAUDE.md
  • package.json
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/__tests__/workflows/**/*.test.{ts,tsx} : Test end-to-end user flows in __tests__/workflows/ directory

Applied to files:

  • src/__tests__/components/SaveShare.test.tsx
  • src/__tests__/workflows/share-lifecycle.test.ts
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to **/*.{ts,tsx} : Use @/ path alias for imports instead of relative paths

Applied to files:

  • tsconfig.test.json
  • webpack.config.cjs
📚 Learning: 2026-01-02T23:50:29.859Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T23:50:29.859Z
Learning: Applies to src/{components,lib,types}/**/*.{ts,tsx} : UI components sit under `src/components/`, helpers in `src/lib/`, shared types in `src/types/`

Applied to files:

  • tsconfig.test.json
  • CLAUDE.md
📚 Learning: 2026-01-02T23:50:29.859Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T23:50:29.859Z
Learning: Debug flaky Electron tests with `npm test -- --runInBand` to serialize execution

Applied to files:

  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/__tests__/setup.ts
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Use props and callbacks for component communication instead of external state libraries like Redux

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-01-02T23:50:29.859Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T23:50:29.859Z
Learning: PRs should describe the change set, include screenshots or recordings for UI tweaks, and list run commands (`npm test`, `npm run lint`)

Applied to files:

  • package.json
🧬 Code graph analysis (16)
src/lib/clientShareManager.ts (1)
src/types/index.ts (1)
  • IglooShare (44-55)
src/__tests__/components/AddShare.test.tsx (1)
src/__tests__/setup.ts (1)
  • mockElectronAPI (191-191)
src/components/Create.tsx (1)
src/lib/validation.ts (3)
  • validateShareName (389-419)
  • VALIDATION_LIMITS (4-15)
  • validatePositiveInteger (335-369)
src/__tests__/integration/clientShareManager.test.ts (2)
src/__tests__/setup.ts (1)
  • mockElectronAPI (191-191)
src/lib/clientShareManager.ts (1)
  • clientShareManager (98-98)
src/components/AddShare.tsx (2)
src/lib/validation.ts (2)
  • VALIDATION_LIMITS (4-15)
  • sanitizeUserError (432-458)
src/types/index.ts (1)
  • DecodedGroup (9-19)
src/__tests__/integration/computeRelayPlan.test.ts (1)
src/__tests__/setup.ts (1)
  • mockElectronAPI (191-191)
src/preload.ts (1)
src/lib/echoRelays.ts (1)
  • RelayPlan (134-141)
src/main.ts (1)
src/lib/echoRelays.ts (1)
  • computeRelayPlan (151-227)
src/__tests__/components/SaveShare.test.tsx (1)
src/lib/encryption.ts (1)
  • derive_secret_async (24-73)
src/__tests__/integration/electron-security.test.ts (1)
webpack.config.cjs (1)
  • path (1-1)
src/__tests__/workflows/share-lifecycle.test.ts (2)
src/__tests__/setup.ts (2)
  • mockElectronAPI (191-191)
  • mockDeriveSecret (136-136)
src/lib/clientShareManager.ts (1)
  • clientShareManager (98-98)
src/components/LoadShare.tsx (1)
src/lib/validation.ts (2)
  • VALIDATION_LIMITS (4-15)
  • sanitizeUserError (432-458)
src/__tests__/lib/echoRelays.test.ts (1)
src/lib/echoRelays.ts (2)
  • normalizeRelayUrl (229-229)
  • computeRelayPlan (151-227)
src/components/SaveShare.tsx (1)
src/lib/validation.ts (1)
  • VALIDATION_LIMITS (4-15)
src/components/Recover.tsx (1)
src/lib/validation.ts (1)
  • VALIDATION_LIMITS (4-15)
src/__tests__/lib/validation.test.ts (1)
src/lib/validation.ts (7)
  • VALIDATION_LIMITS (4-15)
  • validatePassword (32-49)
  • validatePasswordLength (467-487)
  • validatePositiveInteger (335-369)
  • validateShareName (389-419)
  • sanitizeUserError (432-458)
  • formatRelayUrl (230-304)
🪛 LanguageTool
SECURITY_AUDIT_2026-01-06.md

[grammar] ~269-~269: Use a hyphen to join words.
Context: ...m invalid threshold values --- ## High Severity Issues ### 6. ✅ FIXED: Insecur...

(QB_NEW_EN_HYPHEN)


[grammar] ~838-~838: Use a hyphen to join words.
Context: ...")` = NaN silently accepted --- ## Low Severity Issues ### 33. ✅ FIXED: No IPC...

(QB_NEW_EN_HYPHEN)


[grammar] ~976-~976: Use a hyphen to join words.
Context: ...ion fixes covering all critical and high severity React component validation issu...

(QB_NEW_EN_HYPHEN)

Copy link
Copy Markdown
Contributor

@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 @src/lib/echoRelays.ts:
- Around line 134-141: Consolidate the duplicated RelayPlan by creating a single
exported interface RelayPlan in the project's shared types directory (use
interface, not type) with the fields relays, envRelays, defaultRelays,
groupRelays, explicitRelays, and groupExtras; then remove the local RelayPlan
definitions and import this shared RelayPlan in both the echoRelays module and
the preload module so both files reference the same interface.
🧹 Nitpick comments (9)
src/__tests__/lib/validation.test.ts (1)

65-70: Verify completeness of max-length password test.

The test checks hasMaxLength and hasMinLength but doesn't verify isValid. Since the password 'Aa1!' + 'x'.repeat(252) should satisfy all requirements (uppercase, lowercase, number, special char, length), consider asserting result.isValid to ensure the complete validation logic works correctly.

✨ Suggested addition
   it('should accept passwords at max length', () => {
     const maxPassword = 'Aa1!' + 'x'.repeat(252);
     const result = validatePassword(maxPassword);
     expect(result.hasMaxLength).toBe(true);
     expect(result.hasMinLength).toBe(true);
+    expect(result.isValid).toBe(true);
   });
src/__tests__/components/Recover.test.tsx (1)

426-435: Consider making mask length assertion less brittle.

The regex /•{40}/ assumes a specific number of mask characters. If the masking logic changes (e.g., different NSEC lengths), this test could break unexpectedly.

♻️ Suggestion: Use a more flexible assertion
-      expect(screen.getByText(/•{40}/)).toBeInTheDocument();
+      // Assert that masked characters exist without hard-coding count
+      expect(screen.getByText(/•+/)).toBeInTheDocument();

Alternatively, assert that the full NSEC is not visible while some masked portion is, which you already do.

src/components/AddShare.tsx (1)

395-409: Inline type definition could be extracted for reuse.

The LegacyDecodedGroup type is defined inline within the function. If this pattern is needed elsewhere, consider extracting it to src/types/index.ts.

src/__tests__/integration/computeRelayPlan.test.ts (1)

26-68: Static analysis tests are effective but may be fragile.

Testing by reading source file content and using regex patterns is unconventional but provides valuable verification that IPC handlers are registered correctly. However, these tests may break if code formatting or structure changes without functional impact.

Consider adding a comment noting that these tests verify contract/structure and may need updates during refactoring:

  describe('Handler Registration (static analysis)', () => {
+    // NOTE: These regex-based tests verify handler structure in main.ts.
+    // If formatting changes cause failures, update patterns as needed.
    it('should register compute-relay-plan IPC handler', () => {
src/components/Recover.tsx (2)

751-754: Consider whether revealing the NSEC prefix is acceptable.

The masked display shows the first 8 characters of the NSEC ({recoveredNsec.substring(0, 8)}). While this helps users confirm they have the correct key, NSEC prefixes are predictable (nsec1...), so this is low risk. However, if future key formats include identifying info in the prefix, this could leak data.

🔒 Optional: Use a fully masked placeholder
              ) : (
                <div className="text-xs font-mono text-gray-400">
-                  {recoveredNsec.substring(0, 8)}{'•'.repeat(40)}...
+                  {'•'.repeat(48)}...
                </div>
              )}

461-462: Avoid logging error details for clipboard operations.

The console.error('Failed to copy NSEC:', err) may expose error stack traces or internal details. Consider logging only a generic message.

🔒 Suggested fix
     } catch (err) {
-      console.error('Failed to copy NSEC:', err);
+      console.error('[Recover] Clipboard write failed');
src/lib/validation.ts (1)

184-199: Consider IPv6 localhost and link-local addresses for SSRF protection.

The current implementation blocks IPv4 private ranges and localhost, but IPv6 equivalents like ::1, ::ffff:127.0.0.1, or fe80:: link-local addresses could bypass these checks. Relay URLs might accept IPv6 addresses.

🔒 Add IPv6 SSRF protection
  // SSRF Protection: Block localhost
  if (host === 'localhost') return false;
+
+ // SSRF Protection: Block IPv6 loopback and mapped addresses
+ if (host === '::1' || host === '[::1]') return false;
+ if (host.startsWith('::ffff:')) return false;

  // Validate the host part

Or alternatively, validate IPv6 addresses in a separate function before the domain pattern check.

SECURITY_AUDIT_2026-01-06.md (2)

269-269: Grammar: Use hyphens for compound modifiers before nouns.

Three instances flagged by static analysis:

  • Line 269: "Early return prevents state explosion from invalid threshold values --- ## High Severity Issues" → suggest "High-Severity"
  • Line 838: "Number("") = 0 and Number("abc") = NaN silently accepted --- ## Low Severity Issues" → suggest "Low-Severity"
  • Line 976: "all critical and high severity React component validation issues" → suggest "critical and high-severity"

Also applies to: 838-838, 976-976


18-18: Clarify discrepancy in issue count—summary table vs. statistics table.

Line 18 states: "⚠️ Open | 23 | Issues requiring future attention"

But line 51 (Executive Summary table) shows:

  • Critical: 5 fixed, 0 remaining ✓
  • High: 7 fixed, 3 remaining
  • Medium: 4 fixed, 13 remaining
  • Low: 2 fixed, 7 remaining

Total remaining: 3 + 13 + 7 = 23

Counts match, but the visibility of open HIGH/MEDIUM issues in the summary table would help stakeholders understand the risk profile at a glance. Consider adding a "Remaining by Severity" breakdown near line 18.

Also applies to: 51-51

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1bb4086 and 4933022.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (37)
  • CLAUDE.md
  • SECURITY_AUDIT_2026-01-06.md
  • index.html
  • package.json
  • src/__tests__/__mocks__/bifrost.mock.ts
  • src/__tests__/components/AddShare.test.tsx
  • src/__tests__/components/LoadShare.test.tsx
  • src/__tests__/components/Recover.test.tsx
  • src/__tests__/components/SaveShare.test.tsx
  • src/__tests__/components/Signer.test.tsx
  • src/__tests__/integration/clientShareManager.test.ts
  • src/__tests__/integration/computeRelayPlan.test.ts
  • src/__tests__/integration/electron-security.test.ts
  • src/__tests__/integration/userInputValidation.test.ts
  • src/__tests__/lib/echoRelays.test.ts
  • src/__tests__/lib/igloo-core-integration.test.ts
  • src/__tests__/lib/shareManager.test.ts
  • src/__tests__/lib/validation.test.ts
  • src/__tests__/setup.ts
  • src/__tests__/workflows/keyset-creation.test.ts
  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/components/AddShare.tsx
  • src/components/Create.tsx
  • src/components/Keyset.tsx
  • src/components/LoadShare.tsx
  • src/components/Recover.tsx
  • src/components/SaveShare.tsx
  • src/components/Signer.tsx
  • src/lib/clientShareManager.ts
  • src/lib/echoRelays.ts
  • src/lib/shareManager.ts
  • src/lib/validation.ts
  • src/main.ts
  • src/preload.ts
  • tsconfig.preload.json
  • tsconfig.test.json
  • webpack.config.cjs
🧰 Additional context used
📓 Path-based instructions (17)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Use strict TypeScript mode with explicit types for function parameters and returns
Prefer interfaces over types for defining object shapes in TypeScript
Use @/ path alias for imports instead of relative paths
Use camelCase for functions and variables
Use UPPER_SNAKE_CASE for constants

Files:

  • src/__tests__/lib/shareManager.test.ts
  • src/__tests__/components/AddShare.test.tsx
  • src/__tests__/lib/igloo-core-integration.test.ts
  • src/__tests__/integration/userInputValidation.test.ts
  • src/components/LoadShare.tsx
  • src/components/Recover.tsx
  • src/__tests__/__mocks__/bifrost.mock.ts
  • src/__tests__/lib/echoRelays.test.ts
  • src/lib/shareManager.ts
  • src/components/Signer.tsx
  • src/lib/echoRelays.ts
  • src/__tests__/components/Recover.test.tsx
  • src/__tests__/setup.ts
  • src/components/Create.tsx
  • src/components/Keyset.tsx
  • src/__tests__/components/SaveShare.test.tsx
  • src/lib/clientShareManager.ts
  • src/components/AddShare.tsx
  • src/__tests__/integration/electron-security.test.ts
  • src/__tests__/integration/computeRelayPlan.test.ts
  • src/__tests__/workflows/keyset-creation.test.ts
  • src/preload.ts
  • src/__tests__/lib/validation.test.ts
  • src/lib/validation.ts
  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/components/SaveShare.tsx
  • src/__tests__/integration/clientShareManager.test.ts
  • src/__tests__/components/Signer.test.tsx
  • src/main.ts
  • src/__tests__/components/LoadShare.test.tsx
src/__tests__/**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

src/__tests__/**/*.test.{ts,tsx}: Mock @frostr/igloo-core functions at the module level in tests to avoid ESM/Jest complications
Use jest.clearAllMocks() in beforeEach hooks to ensure test isolation
Mock Electron's ipcRenderer and app APIs in tests

Files:

  • src/__tests__/lib/shareManager.test.ts
  • src/__tests__/components/AddShare.test.tsx
  • src/__tests__/lib/igloo-core-integration.test.ts
  • src/__tests__/integration/userInputValidation.test.ts
  • src/__tests__/lib/echoRelays.test.ts
  • src/__tests__/components/Recover.test.tsx
  • src/__tests__/components/SaveShare.test.tsx
  • src/__tests__/integration/electron-security.test.ts
  • src/__tests__/integration/computeRelayPlan.test.ts
  • src/__tests__/workflows/keyset-creation.test.ts
  • src/__tests__/lib/validation.test.ts
  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/__tests__/integration/clientShareManager.test.ts
  • src/__tests__/components/Signer.test.tsx
  • src/__tests__/components/LoadShare.test.tsx
src/__tests__/lib/**/*.test.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Test utility functions in tests/lib/ directory

Files:

  • src/__tests__/lib/shareManager.test.ts
  • src/__tests__/lib/igloo-core-integration.test.ts
  • src/__tests__/lib/echoRelays.test.ts
  • src/__tests__/lib/validation.test.ts
src/__tests__/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Tests mirror runtime code under src/__tests__/ with integration/, performance/, and __mocks__/ subdirectories for feature-specific coverage

Files:

  • src/__tests__/lib/shareManager.test.ts
  • src/__tests__/components/AddShare.test.tsx
  • src/__tests__/lib/igloo-core-integration.test.ts
  • src/__tests__/integration/userInputValidation.test.ts
  • src/__tests__/__mocks__/bifrost.mock.ts
  • src/__tests__/lib/echoRelays.test.ts
  • src/__tests__/components/Recover.test.tsx
  • src/__tests__/setup.ts
  • src/__tests__/components/SaveShare.test.tsx
  • src/__tests__/integration/electron-security.test.ts
  • src/__tests__/integration/computeRelayPlan.test.ts
  • src/__tests__/workflows/keyset-creation.test.ts
  • src/__tests__/lib/validation.test.ts
  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/__tests__/integration/clientShareManager.test.ts
  • src/__tests__/components/Signer.test.tsx
  • src/__tests__/components/LoadShare.test.tsx
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.{ts,tsx}: All runtime code is TypeScript with two-space indentation and required semicolons
Import third-party packages before internal modules and use the @/ alias for local paths

Files:

  • src/__tests__/lib/shareManager.test.ts
  • src/__tests__/components/AddShare.test.tsx
  • src/__tests__/lib/igloo-core-integration.test.ts
  • src/__tests__/integration/userInputValidation.test.ts
  • src/components/LoadShare.tsx
  • src/components/Recover.tsx
  • src/__tests__/__mocks__/bifrost.mock.ts
  • src/__tests__/lib/echoRelays.test.ts
  • src/lib/shareManager.ts
  • src/components/Signer.tsx
  • src/lib/echoRelays.ts
  • src/__tests__/components/Recover.test.tsx
  • src/__tests__/setup.ts
  • src/components/Create.tsx
  • src/components/Keyset.tsx
  • src/__tests__/components/SaveShare.test.tsx
  • src/lib/clientShareManager.ts
  • src/components/AddShare.tsx
  • src/__tests__/integration/electron-security.test.ts
  • src/__tests__/integration/computeRelayPlan.test.ts
  • src/__tests__/workflows/keyset-creation.test.ts
  • src/preload.ts
  • src/__tests__/lib/validation.test.ts
  • src/lib/validation.ts
  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/components/SaveShare.tsx
  • src/__tests__/integration/clientShareManager.test.ts
  • src/__tests__/components/Signer.test.tsx
  • src/main.ts
  • src/__tests__/components/LoadShare.test.tsx
src/**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Jest with Testing Library powers renderer specs; place new tests beside features as <subject>.test.tsx

Files:

  • src/__tests__/lib/shareManager.test.ts
  • src/__tests__/components/AddShare.test.tsx
  • src/__tests__/lib/igloo-core-integration.test.ts
  • src/__tests__/integration/userInputValidation.test.ts
  • src/__tests__/lib/echoRelays.test.ts
  • src/__tests__/components/Recover.test.tsx
  • src/__tests__/components/SaveShare.test.tsx
  • src/__tests__/integration/electron-security.test.ts
  • src/__tests__/integration/computeRelayPlan.test.ts
  • src/__tests__/workflows/keyset-creation.test.ts
  • src/__tests__/lib/validation.test.ts
  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/__tests__/integration/clientShareManager.test.ts
  • src/__tests__/components/Signer.test.tsx
  • src/__tests__/components/LoadShare.test.tsx
src/__tests__/components/**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Test React component behavior in tests/components/ directory

Files:

  • src/__tests__/components/AddShare.test.tsx
  • src/__tests__/components/Recover.test.tsx
  • src/__tests__/components/SaveShare.test.tsx
  • src/__tests__/components/Signer.test.tsx
  • src/__tests__/components/LoadShare.test.tsx
src/__tests__/integration/**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Test Electron IPC communication in tests/integration/ directory

Files:

  • src/__tests__/integration/userInputValidation.test.ts
  • src/__tests__/integration/electron-security.test.ts
  • src/__tests__/integration/computeRelayPlan.test.ts
  • src/__tests__/integration/clientShareManager.test.ts
src/components/[A-Z]*.tsx

📄 CodeRabbit inference engine (CLAUDE.md)

Use PascalCase for component files

Files:

  • src/components/LoadShare.tsx
  • src/components/Recover.tsx
  • src/components/Signer.tsx
  • src/components/Create.tsx
  • src/components/Keyset.tsx
  • src/components/AddShare.tsx
  • src/components/SaveShare.tsx
src/components/**/*.tsx

📄 CodeRabbit inference engine (CLAUDE.md)

src/components/**/*.tsx: Use Tailwind CSS utility classes in JSX and use cn() utility for conditional classes
Avoid inline styles unless conditionally computed
Use functional components with hooks instead of class components
Use ipcRenderer.invoke() in renderer process to call IPC handlers without direct file system access

Tailwind utility classes style JSX; reserve inline styles for dynamic values only

Files:

  • src/components/LoadShare.tsx
  • src/components/Recover.tsx
  • src/components/Signer.tsx
  • src/components/Create.tsx
  • src/components/Keyset.tsx
  • src/components/AddShare.tsx
  • src/components/SaveShare.tsx
src/{components,lib,types}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

UI components sit under src/components/, helpers in src/lib/, shared types in src/types/

Files:

  • src/components/LoadShare.tsx
  • src/components/Recover.tsx
  • src/lib/shareManager.ts
  • src/components/Signer.tsx
  • src/lib/echoRelays.ts
  • src/components/Create.tsx
  • src/components/Keyset.tsx
  • src/lib/clientShareManager.ts
  • src/components/AddShare.tsx
  • src/lib/validation.ts
  • src/components/SaveShare.tsx
src/components/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

src/components/**/*.{ts,tsx}: Prefer functional React components; name them in PascalCase and helpers in camelCase
Components in src/components/ follow kebab-case filenames (e.g., share-list.tsx)

Files:

  • src/components/LoadShare.tsx
  • src/components/Recover.tsx
  • src/components/Signer.tsx
  • src/components/Create.tsx
  • src/components/Keyset.tsx
  • src/components/AddShare.tsx
  • src/components/SaveShare.tsx
src/__tests__/__mocks__/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Place shared mock implementations in tests/mocks/ for use across test files

Files:

  • src/__tests__/__mocks__/bifrost.mock.ts
src/__tests__/{setup.ts,__mocks__/**}

📄 CodeRabbit inference engine (AGENTS.md)

Register shared mocks in src/__tests__/setup.ts and reuse fixtures from src/__tests__/__mocks__/

Files:

  • src/__tests__/__mocks__/bifrost.mock.ts
  • src/__tests__/setup.ts
src/lib/shareManager.ts

📄 CodeRabbit inference engine (CLAUDE.md)

src/lib/shareManager.ts: Never store plaintext share data; always encrypt with user passwords
Store shares in /igloo/shares/ directory using the defined JSON schema

Files:

  • src/lib/shareManager.ts
src/__tests__/workflows/**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Test end-to-end user flows in tests/workflows/ directory

Files:

  • src/__tests__/workflows/keyset-creation.test.ts
  • src/__tests__/workflows/share-lifecycle.test.ts
src/main.ts

📄 CodeRabbit inference engine (CLAUDE.md)

src/main.ts: Register IPC handlers in main.ts using ipcMain.handle() for file system operations
Electron's main process uses CommonJS (require) while renderer uses ESM (import)

Main Electron process lives in src/main.ts; the renderer bootstraps from src/renderer.tsx

Files:

  • src/main.ts
🧠 Learnings (28)
📓 Common learnings
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T23:50:29.859Z
Learning: Applies to src/**/*ipc*.{ts,tsx} : Cover new IPC handlers with unit tests plus at least one scenario in `src/__tests__/integration/`
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/lib/shareManager.ts : Store shares in <appData>/igloo/shares/ directory using the defined JSON schema

Applied to files:

  • src/__tests__/lib/shareManager.test.ts
  • src/components/Recover.tsx
  • src/lib/shareManager.ts
  • src/lib/clientShareManager.ts
  • src/components/AddShare.tsx
  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/__tests__/integration/clientShareManager.test.ts
  • CLAUDE.md
  • src/main.ts
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/__tests__/lib/**/*.test.ts : Test utility functions in __tests__/lib/ directory

Applied to files:

  • src/__tests__/lib/shareManager.test.ts
  • src/__tests__/components/AddShare.test.tsx
  • src/__tests__/lib/igloo-core-integration.test.ts
  • src/__tests__/lib/echoRelays.test.ts
  • src/__tests__/components/Recover.test.tsx
  • src/__tests__/components/SaveShare.test.tsx
  • src/__tests__/integration/electron-security.test.ts
  • src/__tests__/integration/computeRelayPlan.test.ts
  • src/__tests__/lib/validation.test.ts
  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/__tests__/integration/clientShareManager.test.ts
  • CLAUDE.md
  • src/__tests__/components/LoadShare.test.tsx
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/lib/shareManager.ts : Never store plaintext share data; always encrypt with user passwords

Applied to files:

  • src/__tests__/lib/shareManager.test.ts
  • src/__tests__/components/AddShare.test.tsx
  • src/components/LoadShare.tsx
  • src/components/Recover.tsx
  • src/__tests__/__mocks__/bifrost.mock.ts
  • src/lib/shareManager.ts
  • src/components/Keyset.tsx
  • src/__tests__/components/SaveShare.test.tsx
  • src/lib/clientShareManager.ts
  • src/components/AddShare.tsx
  • src/__tests__/workflows/keyset-creation.test.ts
  • src/__tests__/workflows/share-lifecycle.test.ts
  • SECURITY_AUDIT_2026-01-06.md
  • src/components/SaveShare.tsx
  • src/__tests__/integration/clientShareManager.test.ts
  • CLAUDE.md
  • src/__tests__/components/LoadShare.test.tsx
📚 Learning: 2026-01-02T23:50:29.859Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T23:50:29.859Z
Learning: Applies to src/**/*ipc*.{ts,tsx} : Cover new IPC handlers with unit tests plus at least one scenario in `src/__tests__/integration/`

Applied to files:

  • src/__tests__/lib/shareManager.test.ts
  • src/__tests__/components/AddShare.test.tsx
  • src/__tests__/lib/igloo-core-integration.test.ts
  • src/__tests__/integration/userInputValidation.test.ts
  • src/__tests__/lib/echoRelays.test.ts
  • src/__tests__/components/Recover.test.tsx
  • src/__tests__/setup.ts
  • src/__tests__/components/SaveShare.test.tsx
  • src/lib/clientShareManager.ts
  • src/components/AddShare.tsx
  • src/__tests__/integration/electron-security.test.ts
  • src/__tests__/integration/computeRelayPlan.test.ts
  • src/__tests__/lib/validation.test.ts
  • src/__tests__/workflows/share-lifecycle.test.ts
  • SECURITY_AUDIT_2026-01-06.md
  • src/__tests__/integration/clientShareManager.test.ts
  • src/__tests__/components/Signer.test.tsx
  • src/main.ts
  • src/__tests__/components/LoadShare.test.tsx
📚 Learning: 2026-01-02T23:50:29.859Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T23:50:29.859Z
Learning: Applies to src/__tests__/**/*.{ts,tsx} : Tests mirror runtime code under `src/__tests__/` with `integration/`, `performance/`, and `__mocks__/` subdirectories for feature-specific coverage

Applied to files:

  • src/__tests__/lib/shareManager.test.ts
  • src/__tests__/components/AddShare.test.tsx
  • src/__tests__/lib/igloo-core-integration.test.ts
  • src/__tests__/lib/echoRelays.test.ts
  • src/__tests__/components/Recover.test.tsx
  • src/__tests__/setup.ts
  • src/__tests__/components/SaveShare.test.tsx
  • src/__tests__/integration/electron-security.test.ts
  • src/__tests__/integration/computeRelayPlan.test.ts
  • src/__tests__/lib/validation.test.ts
  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/__tests__/integration/clientShareManager.test.ts
  • src/__tests__/components/Signer.test.tsx
  • src/__tests__/components/LoadShare.test.tsx
  • tsconfig.test.json
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/__tests__/__mocks__/**/*.ts : Place shared mock implementations in __tests__/__mocks__/ for use across test files

Applied to files:

  • src/__tests__/lib/shareManager.test.ts
  • src/__tests__/components/AddShare.test.tsx
  • src/__tests__/lib/igloo-core-integration.test.ts
  • src/__tests__/__mocks__/bifrost.mock.ts
  • src/__tests__/setup.ts
  • src/__tests__/components/SaveShare.test.tsx
  • src/__tests__/workflows/keyset-creation.test.ts
  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/__tests__/integration/clientShareManager.test.ts
  • tsconfig.test.json
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/__tests__/integration/**/*.test.{ts,tsx} : Test Electron IPC communication in __tests__/integration/ directory

Applied to files:

  • src/__tests__/lib/shareManager.test.ts
  • src/__tests__/components/AddShare.test.tsx
  • src/__tests__/lib/igloo-core-integration.test.ts
  • src/__tests__/integration/userInputValidation.test.ts
  • src/__tests__/lib/echoRelays.test.ts
  • src/__tests__/components/Recover.test.tsx
  • src/__tests__/setup.ts
  • src/lib/clientShareManager.ts
  • src/components/AddShare.tsx
  • src/__tests__/integration/electron-security.test.ts
  • src/__tests__/integration/computeRelayPlan.test.ts
  • src/preload.ts
  • src/__tests__/lib/validation.test.ts
  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/__tests__/integration/clientShareManager.test.ts
  • CLAUDE.md
  • src/main.ts
  • src/__tests__/components/LoadShare.test.tsx
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/__tests__/**/*.test.{ts,tsx} : Mock frostr/igloo-core functions at the module level in tests to avoid ESM/Jest complications

Applied to files:

  • src/__tests__/lib/shareManager.test.ts
  • package.json
  • src/__tests__/components/AddShare.test.tsx
  • src/__tests__/lib/igloo-core-integration.test.ts
  • src/__tests__/__mocks__/bifrost.mock.ts
  • src/__tests__/lib/echoRelays.test.ts
  • src/__tests__/components/Recover.test.tsx
  • src/__tests__/setup.ts
  • src/__tests__/workflows/keyset-creation.test.ts
  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/__tests__/integration/clientShareManager.test.ts
  • src/__tests__/components/Signer.test.tsx
  • tsconfig.test.json
📚 Learning: 2026-01-02T23:50:29.859Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T23:50:29.859Z
Learning: PRs should describe the change set, include screenshots or recordings for UI tweaks, and list run commands (`npm test`, `npm run lint`)

Applied to files:

  • package.json
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/main.ts : Electron's main process uses CommonJS (require) while renderer uses ESM (import)

Applied to files:

  • package.json
  • webpack.config.cjs
  • src/__tests__/setup.ts
  • src/__tests__/integration/electron-security.test.ts
  • src/preload.ts
  • CLAUDE.md
📚 Learning: 2026-01-02T23:50:29.859Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T23:50:29.859Z
Learning: Applies to src/main.ts : Main Electron process lives in `src/main.ts`; the renderer bootstraps from `src/renderer.tsx`

Applied to files:

  • package.json
  • webpack.config.cjs
  • src/__tests__/integration/electron-security.test.ts
  • src/preload.ts
  • CLAUDE.md
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/__tests__/**/*.test.{ts,tsx} : Mock Electron's ipcRenderer and app APIs in tests

Applied to files:

  • src/__tests__/components/AddShare.test.tsx
  • webpack.config.cjs
  • src/__tests__/components/Recover.test.tsx
  • src/__tests__/setup.ts
  • src/__tests__/integration/electron-security.test.ts
  • src/__tests__/integration/computeRelayPlan.test.ts
  • src/preload.ts
  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/__tests__/integration/clientShareManager.test.ts
  • src/__tests__/components/Signer.test.tsx
  • src/main.ts
📚 Learning: 2026-01-02T23:50:29.859Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T23:50:29.859Z
Learning: Applies to src/__tests__/{setup.ts,__mocks__/**} : Register shared mocks in `src/__tests__/setup.ts` and reuse fixtures from `src/__tests__/__mocks__/`

Applied to files:

  • src/__tests__/components/AddShare.test.tsx
  • src/__tests__/lib/igloo-core-integration.test.ts
  • src/__tests__/__mocks__/bifrost.mock.ts
  • src/__tests__/components/Recover.test.tsx
  • src/__tests__/setup.ts
  • src/__tests__/components/SaveShare.test.tsx
  • src/__tests__/workflows/keyset-creation.test.ts
  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/__tests__/integration/clientShareManager.test.ts
  • src/__tests__/components/Signer.test.tsx
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/__tests__/**/*.test.{ts,tsx} : Use jest.clearAllMocks() in beforeEach hooks to ensure test isolation

Applied to files:

  • src/__tests__/components/AddShare.test.tsx
  • src/__tests__/components/Recover.test.tsx
  • src/__tests__/setup.ts
  • src/__tests__/workflows/keyset-creation.test.ts
  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/__tests__/integration/clientShareManager.test.ts
  • tsconfig.test.json
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/__tests__/components/**/*.test.{ts,tsx} : Test React component behavior in __tests__/components/ directory

Applied to files:

  • src/__tests__/components/AddShare.test.tsx
  • src/__tests__/components/Recover.test.tsx
  • src/__tests__/components/SaveShare.test.tsx
  • src/__tests__/integration/electron-security.test.ts
  • src/__tests__/components/LoadShare.test.tsx
  • tsconfig.test.json
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/lib/encryption.ts : Use PBKDF2 with 600,000 iterations for encrypting share files

Applied to files:

  • src/components/LoadShare.tsx
  • src/__tests__/__mocks__/bifrost.mock.ts
  • src/components/SaveShare.tsx
📚 Learning: 2026-01-02T23:50:29.859Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T23:50:29.859Z
Learning: Applies to src/**/*.{ts,tsx} : Import third-party packages before internal modules and use the `@/` alias for local paths

Applied to files:

  • webpack.config.cjs
  • tsconfig.preload.json
  • CLAUDE.md
  • tsconfig.test.json
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to **/*.{ts,tsx} : Use @/ path alias for imports instead of relative paths

Applied to files:

  • webpack.config.cjs
  • tsconfig.test.json
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/__tests__/workflows/**/*.test.{ts,tsx} : Test end-to-end user flows in __tests__/workflows/ directory

Applied to files:

  • src/__tests__/lib/echoRelays.test.ts
  • src/__tests__/components/SaveShare.test.tsx
  • src/__tests__/workflows/share-lifecycle.test.ts
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Do not implement cryptographic logic in the desktop app; delegate all crypto operations to frostr/igloo-core

Applied to files:

  • src/components/Signer.tsx
  • src/components/AddShare.tsx
  • CLAUDE.md
📚 Learning: 2026-01-02T23:50:29.859Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T23:50:29.859Z
Learning: Applies to src/**/*.test.{ts,tsx} : Jest with Testing Library powers renderer specs; place new tests beside features as `<subject>.test.tsx`

Applied to files:

  • src/__tests__/components/Recover.test.tsx
  • src/__tests__/setup.ts
  • src/__tests__/integration/electron-security.test.ts
  • src/__tests__/lib/validation.test.ts
  • src/__tests__/components/Signer.test.tsx
  • tsconfig.test.json
📚 Learning: 2026-01-02T23:50:29.859Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T23:50:29.859Z
Learning: Debug flaky Electron tests with `npm test -- --runInBand` to serialize execution

Applied to files:

  • src/__tests__/setup.ts
  • src/__tests__/integration/electron-security.test.ts
  • src/__tests__/workflows/share-lifecycle.test.ts
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/components/**/*.tsx : Use ipcRenderer.invoke() in renderer process to call IPC handlers without direct file system access

Applied to files:

  • src/__tests__/setup.ts
  • src/components/Keyset.tsx
  • src/lib/clientShareManager.ts
  • src/__tests__/integration/electron-security.test.ts
  • src/__tests__/integration/computeRelayPlan.test.ts
  • src/preload.ts
  • src/__tests__/integration/clientShareManager.test.ts
  • src/main.ts
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/main.ts : Register IPC handlers in main.ts using ipcMain.handle() for file system operations

Applied to files:

  • src/components/Keyset.tsx
  • src/lib/clientShareManager.ts
  • src/__tests__/integration/electron-security.test.ts
  • src/__tests__/integration/computeRelayPlan.test.ts
  • src/preload.ts
  • src/main.ts
📚 Learning: 2026-01-02T23:50:29.859Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T23:50:29.859Z
Learning: Applies to src/**/*.{ts,tsx} : All runtime code is TypeScript with two-space indentation and required semicolons

Applied to files:

  • tsconfig.preload.json
  • tsconfig.test.json
📚 Learning: 2026-01-02T23:50:29.859Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T23:50:29.859Z
Learning: Applies to src/{components,lib,types}/**/*.{ts,tsx} : UI components sit under `src/components/`, helpers in `src/lib/`, shared types in `src/types/`

Applied to files:

  • CLAUDE.md
  • tsconfig.test.json
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Use props and callbacks for component communication instead of external state libraries like Redux

Applied to files:

  • CLAUDE.md
🧬 Code graph analysis (16)
src/components/LoadShare.tsx (1)
src/lib/validation.ts (2)
  • VALIDATION_LIMITS (4-15)
  • sanitizeUserError (432-458)
src/components/Recover.tsx (1)
src/lib/validation.ts (1)
  • VALIDATION_LIMITS (4-15)
src/__tests__/lib/echoRelays.test.ts (1)
src/lib/echoRelays.ts (1)
  • computeRelayPlan (151-227)
src/lib/echoRelays.ts (1)
src/preload.ts (1)
  • RelayPlan (14-21)
src/components/Create.tsx (1)
src/lib/validation.ts (3)
  • validateShareName (389-419)
  • VALIDATION_LIMITS (4-15)
  • validatePositiveInteger (335-369)
src/components/Keyset.tsx (1)
src/components/ui/button.tsx (1)
  • Button (56-56)
src/__tests__/components/SaveShare.test.tsx (1)
src/lib/encryption.ts (1)
  • derive_secret_async (24-73)
src/lib/clientShareManager.ts (1)
src/types/index.ts (1)
  • IglooShare (44-55)
src/components/AddShare.tsx (2)
src/lib/validation.ts (2)
  • VALIDATION_LIMITS (4-15)
  • sanitizeUserError (432-458)
src/types/index.ts (1)
  • DecodedGroup (9-19)
src/__tests__/integration/computeRelayPlan.test.ts (2)
webpack.config.cjs (1)
  • path (1-1)
src/__tests__/setup.ts (1)
  • mockElectronAPI (191-191)
src/preload.ts (1)
src/lib/echoRelays.ts (1)
  • RelayPlan (134-141)
src/__tests__/lib/validation.test.ts (1)
src/lib/validation.ts (7)
  • VALIDATION_LIMITS (4-15)
  • validatePassword (32-49)
  • validatePasswordLength (467-487)
  • validatePositiveInteger (335-369)
  • validateShareName (389-419)
  • sanitizeUserError (432-458)
  • formatRelayUrl (230-304)
src/__tests__/workflows/share-lifecycle.test.ts (2)
src/__tests__/setup.ts (2)
  • mockElectronAPI (191-191)
  • mockDeriveSecret (136-136)
src/lib/clientShareManager.ts (1)
  • clientShareManager (98-98)
src/components/SaveShare.tsx (1)
src/lib/validation.ts (1)
  • VALIDATION_LIMITS (4-15)
src/__tests__/integration/clientShareManager.test.ts (2)
src/__tests__/setup.ts (1)
  • mockElectronAPI (191-191)
src/lib/clientShareManager.ts (1)
  • clientShareManager (98-98)
src/main.ts (1)
src/lib/echoRelays.ts (1)
  • computeRelayPlan (151-227)
🪛 LanguageTool
SECURITY_AUDIT_2026-01-06.md

[grammar] ~269-~269: Use a hyphen to join words.
Context: ...m invalid threshold values --- ## High Severity Issues ### 6. ✅ FIXED: Insecur...

(QB_NEW_EN_HYPHEN)


[grammar] ~838-~838: Use a hyphen to join words.
Context: ...")` = NaN silently accepted --- ## Low Severity Issues ### 33. ✅ FIXED: No IPC...

(QB_NEW_EN_HYPHEN)


[grammar] ~976-~976: Use a hyphen to join words.
Context: ...ion fixes covering all critical and high severity React component validation issu...

(QB_NEW_EN_HYPHEN)

Copy link
Copy Markdown
Contributor

@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: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/main.ts (2)

459-470: Remove unused err variable to fix ESLint warning.

The pipeline reports that err is defined but never used on line 464.

🔧 Suggested fix
           try {
             existing?.cleanup?.();
-          } catch (err) {
+          } catch {
             console.warn('[EchoBridge] Listener cleanup failed on sender destroyed', { listenerId });
           } finally {

495-504: Remove unused err variable to fix ESLint warning.

The pipeline reports that err is defined but never used on line 499.

🔧 Suggested fix
       try {
         existing.cleanup?.();
-      } catch (err) {
+      } catch {
         console.warn('[EchoBridge] Listener cleanup failed on stop', { listenerId });
       } finally {
🤖 Fix all issues with AI agents
In @src/components/AddShare.tsx:
- Around line 419-433: The renderer is reading process.env.IGLOO_DEBUG_ECHO
directly (debugEnv/debugEnabled) which fails under contextIsolation; move debug
detection into the main process and pass it via IPC instead: add a debugEnabled
boolean to the computeRelayPlan IPC response in the main handler (same pattern
used for IGLOO_RELAY), then consume that debugEnabled value in AddShare.tsx when
building the eventConfig for sendEcho so you no longer access process.env from
the renderer; update the sendEcho call site to use the injected debugEnabled
flag and remove direct usage of debugEnv/debugEnabled variables in the renderer.

In @src/main.ts:
- Around line 425-434: The catch block around existing?.cleanup in the
activeEchoListeners handling defines an unused error parameter (err), causing an
ESLint warning; remove the unused parameter by changing the catch signature from
catch (err) to catch { ... } (or rename to catch (_err) if you prefer explicit
unused naming) and keep the existing console.warn('[EchoBridge] Failed to
cleanup existing listener during start', { listenerId }); and the finally block
that deletes from activeEchoListeners to preserve behavior.
- Around line 33-44: The regexes in sanitizeErrorForLog contain unnecessary
backslashes (e.g. '\/' and '[^\/]') that ESLint flags; update each .replace
regex to remove needless escapes for forward slashes and similar characters
while preserving required escapes for backslashes (\\) and quote delimiters.
Specifically, edit the four patterns in sanitizeErrorForLog (the first replace's
/(['"])(\/(?:[^\/]+\/)+)([^\/'"]*)\1/g, the second
/\/(?:[^\/\s:]+\/)+([^\/\s:]+)/g, the third
/(['"])([A-Za-z]:\\(?:[^\\]+\\)+)([^\\'"]*)(\1)/g, and the fourth
/[A-Za-z]:\\(?:[^\\:\s]+\\)+([^\\:\s]+)/g) to use unescaped forward slashes
inside character classes and sequences (e.g. use [^/]+ instead of [^\/]+, and
/\/.../ occurrences inside character classes removed) while keeping backslash
escapes intact for Windows paths.

In @src/preload.ts:
- Line 121: The handler references Electron.IpcRendererEvent but the Electron
types are not imported; import the correct type and update the handler signature
accordingly—add a top-level import like "import type { IpcRendererEvent } from
'electron'" (or "import * as Electron from 'electron'" if you prefer the
namespace) and change the handler parameter from "(_event:
Electron.IpcRendererEvent, data: unknown)" to "(_event: IpcRendererEvent, data:
unknown)" (or keep Electron.IpcRendererEvent if using the namespace import) so
TypeScript/linters recognize the type.
- Line 141: The handler parameter uses the Electron type
Electron.IpcRendererEvent which isn't imported; add the proper Electron type
import in src/preload.ts (e.g., import or import type for IpcRendererEvent from
'electron') and update any existing import statement used at the top of the file
so that Electron.IpcRendererEvent is resolved for the handler function named
handler.
🧹 Nitpick comments (1)
src/lib/echoRelays.ts (1)

170-180: Consider extracting shared deduplication logic.

The dedupe function duplicates the deduplication logic from normalizeList. While the separation makes sense (one normalizes + dedupes, one only dedupes), you could extract the pure deduplication into a shared helper to reduce duplication.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4933022 and 83ad080.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (10)
  • src/__tests__/components/AddShare.test.tsx
  • src/__tests__/integration/computeRelayPlan.test.ts
  • src/__tests__/integration/electron-security.test.ts
  • src/__tests__/lib/ipcSchemas.test.ts
  • src/components/AddShare.tsx
  • src/lib/echoRelays.ts
  • src/lib/ipcSchemas.ts
  • src/main.ts
  • src/preload.ts
  • src/types/index.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/tests/components/AddShare.test.tsx
🧰 Additional context used
📓 Path-based instructions (13)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Use strict TypeScript mode with explicit types for function parameters and returns
Prefer interfaces over types for defining object shapes in TypeScript
Use @/ path alias for imports instead of relative paths
Use camelCase for functions and variables
Use UPPER_SNAKE_CASE for constants

Files:

  • src/components/AddShare.tsx
  • src/__tests__/lib/ipcSchemas.test.ts
  • src/main.ts
  • src/lib/echoRelays.ts
  • src/types/index.ts
  • src/lib/ipcSchemas.ts
  • src/__tests__/integration/electron-security.test.ts
  • src/__tests__/integration/computeRelayPlan.test.ts
  • src/preload.ts
src/components/[A-Z]*.tsx

📄 CodeRabbit inference engine (CLAUDE.md)

Use PascalCase for component files

Files:

  • src/components/AddShare.tsx
src/components/**/*.tsx

📄 CodeRabbit inference engine (CLAUDE.md)

src/components/**/*.tsx: Use Tailwind CSS utility classes in JSX and use cn() utility for conditional classes
Avoid inline styles unless conditionally computed
Use functional components with hooks instead of class components
Use ipcRenderer.invoke() in renderer process to call IPC handlers without direct file system access

Tailwind utility classes style JSX; reserve inline styles for dynamic values only

Files:

  • src/components/AddShare.tsx
src/{components,lib,types}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

UI components sit under src/components/, helpers in src/lib/, shared types in src/types/

Files:

  • src/components/AddShare.tsx
  • src/lib/echoRelays.ts
  • src/types/index.ts
  • src/lib/ipcSchemas.ts
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.{ts,tsx}: All runtime code is TypeScript with two-space indentation and required semicolons
Import third-party packages before internal modules and use the @/ alias for local paths

Files:

  • src/components/AddShare.tsx
  • src/__tests__/lib/ipcSchemas.test.ts
  • src/main.ts
  • src/lib/echoRelays.ts
  • src/types/index.ts
  • src/lib/ipcSchemas.ts
  • src/__tests__/integration/electron-security.test.ts
  • src/__tests__/integration/computeRelayPlan.test.ts
  • src/preload.ts
src/components/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

src/components/**/*.{ts,tsx}: Prefer functional React components; name them in PascalCase and helpers in camelCase
Components in src/components/ follow kebab-case filenames (e.g., share-list.tsx)

Files:

  • src/components/AddShare.tsx
src/__tests__/**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

src/__tests__/**/*.test.{ts,tsx}: Mock @frostr/igloo-core functions at the module level in tests to avoid ESM/Jest complications
Use jest.clearAllMocks() in beforeEach hooks to ensure test isolation
Mock Electron's ipcRenderer and app APIs in tests

Files:

  • src/__tests__/lib/ipcSchemas.test.ts
  • src/__tests__/integration/electron-security.test.ts
  • src/__tests__/integration/computeRelayPlan.test.ts
src/__tests__/lib/**/*.test.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Test utility functions in tests/lib/ directory

Files:

  • src/__tests__/lib/ipcSchemas.test.ts
src/__tests__/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Tests mirror runtime code under src/__tests__/ with integration/, performance/, and __mocks__/ subdirectories for feature-specific coverage

Files:

  • src/__tests__/lib/ipcSchemas.test.ts
  • src/__tests__/integration/electron-security.test.ts
  • src/__tests__/integration/computeRelayPlan.test.ts
src/**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Jest with Testing Library powers renderer specs; place new tests beside features as <subject>.test.tsx

Files:

  • src/__tests__/lib/ipcSchemas.test.ts
  • src/__tests__/integration/electron-security.test.ts
  • src/__tests__/integration/computeRelayPlan.test.ts
src/**/*ipc*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Cover new IPC handlers with unit tests plus at least one scenario in src/__tests__/integration/

Files:

  • src/__tests__/lib/ipcSchemas.test.ts
  • src/lib/ipcSchemas.ts
src/main.ts

📄 CodeRabbit inference engine (CLAUDE.md)

src/main.ts: Register IPC handlers in main.ts using ipcMain.handle() for file system operations
Electron's main process uses CommonJS (require) while renderer uses ESM (import)

Main Electron process lives in src/main.ts; the renderer bootstraps from src/renderer.tsx

Files:

  • src/main.ts
src/__tests__/integration/**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Test Electron IPC communication in tests/integration/ directory

Files:

  • src/__tests__/integration/electron-security.test.ts
  • src/__tests__/integration/computeRelayPlan.test.ts
🧠 Learnings (18)
📓 Common learnings
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T23:50:29.859Z
Learning: Applies to src/**/*ipc*.{ts,tsx} : Cover new IPC handlers with unit tests plus at least one scenario in `src/__tests__/integration/`
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/lib/shareManager.ts : Never store plaintext share data; always encrypt with user passwords

Applied to files:

  • src/components/AddShare.tsx
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/lib/shareManager.ts : Store shares in <appData>/igloo/shares/ directory using the defined JSON schema

Applied to files:

  • src/components/AddShare.tsx
  • src/__tests__/lib/ipcSchemas.test.ts
  • src/main.ts
  • src/lib/ipcSchemas.ts
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/__tests__/integration/**/*.test.{ts,tsx} : Test Electron IPC communication in __tests__/integration/ directory

Applied to files:

  • src/components/AddShare.tsx
  • src/__tests__/lib/ipcSchemas.test.ts
  • src/main.ts
  • src/__tests__/integration/electron-security.test.ts
  • src/__tests__/integration/computeRelayPlan.test.ts
  • src/preload.ts
📚 Learning: 2026-01-02T23:50:29.859Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T23:50:29.859Z
Learning: Applies to src/**/*ipc*.{ts,tsx} : Cover new IPC handlers with unit tests plus at least one scenario in `src/__tests__/integration/`

Applied to files:

  • src/components/AddShare.tsx
  • src/__tests__/lib/ipcSchemas.test.ts
  • src/main.ts
  • src/lib/ipcSchemas.ts
  • src/__tests__/integration/electron-security.test.ts
  • src/__tests__/integration/computeRelayPlan.test.ts
  • src/preload.ts
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Do not implement cryptographic logic in the desktop app; delegate all crypto operations to frostr/igloo-core

Applied to files:

  • src/components/AddShare.tsx
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/__tests__/lib/**/*.test.ts : Test utility functions in __tests__/lib/ directory

Applied to files:

  • src/__tests__/lib/ipcSchemas.test.ts
  • src/__tests__/integration/electron-security.test.ts
  • src/__tests__/integration/computeRelayPlan.test.ts
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/__tests__/**/*.test.{ts,tsx} : Mock Electron's ipcRenderer and app APIs in tests

Applied to files:

  • src/__tests__/lib/ipcSchemas.test.ts
  • src/__tests__/integration/electron-security.test.ts
  • src/__tests__/integration/computeRelayPlan.test.ts
  • src/preload.ts
📚 Learning: 2026-01-02T23:50:29.859Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T23:50:29.859Z
Learning: Applies to src/__tests__/**/*.{ts,tsx} : Tests mirror runtime code under `src/__tests__/` with `integration/`, `performance/`, and `__mocks__/` subdirectories for feature-specific coverage

Applied to files:

  • src/__tests__/lib/ipcSchemas.test.ts
  • src/__tests__/integration/electron-security.test.ts
  • src/__tests__/integration/computeRelayPlan.test.ts
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/main.ts : Register IPC handlers in main.ts using ipcMain.handle() for file system operations

Applied to files:

  • src/main.ts
  • src/__tests__/integration/electron-security.test.ts
  • src/__tests__/integration/computeRelayPlan.test.ts
  • src/preload.ts
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/main.ts : Electron's main process uses CommonJS (require) while renderer uses ESM (import)

Applied to files:

  • src/__tests__/integration/electron-security.test.ts
  • src/preload.ts
📚 Learning: 2026-01-02T23:50:29.859Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T23:50:29.859Z
Learning: Applies to src/main.ts : Main Electron process lives in `src/main.ts`; the renderer bootstraps from `src/renderer.tsx`

Applied to files:

  • src/__tests__/integration/electron-security.test.ts
  • src/preload.ts
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/__tests__/components/**/*.test.{ts,tsx} : Test React component behavior in __tests__/components/ directory

Applied to files:

  • src/__tests__/integration/electron-security.test.ts
📚 Learning: 2026-01-02T23:50:29.859Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T23:50:29.859Z
Learning: Applies to src/**/*.test.{ts,tsx} : Jest with Testing Library powers renderer specs; place new tests beside features as `<subject>.test.tsx`

Applied to files:

  • src/__tests__/integration/electron-security.test.ts
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/__tests__/workflows/**/*.test.{ts,tsx} : Test end-to-end user flows in __tests__/workflows/ directory

Applied to files:

  • src/__tests__/integration/electron-security.test.ts
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/components/**/*.tsx : Use ipcRenderer.invoke() in renderer process to call IPC handlers without direct file system access

Applied to files:

  • src/__tests__/integration/electron-security.test.ts
  • src/__tests__/integration/computeRelayPlan.test.ts
  • src/preload.ts
📚 Learning: 2026-01-02T23:50:29.859Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T23:50:29.859Z
Learning: Debug flaky Electron tests with `npm test -- --runInBand` to serialize execution

Applied to files:

  • src/__tests__/integration/electron-security.test.ts
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/__tests__/**/*.test.{ts,tsx} : Mock frostr/igloo-core functions at the module level in tests to avoid ESM/Jest complications

Applied to files:

  • src/__tests__/integration/electron-security.test.ts
🧬 Code graph analysis (7)
src/components/AddShare.tsx (2)
src/lib/validation.ts (2)
  • VALIDATION_LIMITS (4-15)
  • sanitizeUserError (432-458)
src/types/index.ts (1)
  • DecodedGroup (9-19)
src/__tests__/lib/ipcSchemas.test.ts (1)
src/lib/ipcSchemas.ts (9)
  • ShareIdSchema (14-17)
  • HexSaltSchema (20-23)
  • RelayUrlSchema (26-26)
  • ShareCredentialSchema (29-31)
  • GroupCredentialSchema (34-36)
  • SaveShareSchema (39-67)
  • RelayPlanArgsSchema (70-75)
  • EchoStartArgsSchema (78-87)
  • EchoStopArgsSchema (90-94)
src/main.ts (2)
src/lib/echoRelays.ts (1)
  • computeRelayPlan (143-219)
src/lib/ipcSchemas.ts (5)
  • SaveShareSchema (39-67)
  • ShareIdSchema (14-17)
  • RelayPlanArgsSchema (70-75)
  • EchoStartArgsSchema (78-87)
  • EchoStopArgsSchema (90-94)
src/lib/echoRelays.ts (1)
src/types/index.ts (1)
  • RelayPlan (191-198)
src/__tests__/integration/electron-security.test.ts (1)
webpack.config.cjs (1)
  • path (1-1)
src/__tests__/integration/computeRelayPlan.test.ts (1)
src/__tests__/setup.ts (1)
  • mockElectronAPI (191-191)
src/preload.ts (1)
src/types/index.ts (1)
  • RelayPlan (191-198)
🪛 GitHub Actions: CI
src/main.ts

[warning] 37-37: Unnecessary escape character: / no-useless-escape


[warning] 37-37: Unnecessary escape character: / no-useless-escape


[warning] 39-39: Unnecessary escape character: / no-useless-escape


[warning] 39-39: Unnecessary escape character: / no-useless-escape


[warning] 429-429: 'err' is defined but never used @typescript-eslint/no-unused-vars


[warning] 464-464: 'err' is defined but never used @typescript-eslint/no-unused-vars


[warning] 499-499: 'err' is defined but never used @typescript-eslint/no-unused-vars

src/preload.ts

[error] 121-121: 'Electron' is not defined no-undef

🪛 GitHub Check: Lint and Test (18)
src/preload.ts

[failure] 141-141:
'Electron' is not defined


[failure] 121-121:
'Electron' is not defined

🪛 GitHub Check: Lint and Test (20)
src/preload.ts

[failure] 141-141:
'Electron' is not defined


[failure] 121-121:
'Electron' is not defined

🔇 Additional comments (35)
src/types/index.ts (1)

190-198: LGTM! Clean type definition.

The RelayPlan interface is well-structured with clear property names that describe the different relay categories. The interface follows TypeScript conventions and integrates cleanly with the relay planning utilities.

src/preload.ts (2)

56-84: Excellent runtime validation pattern.

The type guards (isEchoReceivedData and isEchoErrorData) provide strong runtime safety by validating IPC payloads before passing them to renderer callbacks. This prevents malformed data from the main process from causing issues in the renderer.


108-152: Robust event listener implementation.

The implementation correctly:

  • Validates callbacks before registering handlers
  • Returns no-op cleanup functions for invalid callbacks
  • Validates incoming data with type guards
  • Logs malformed data without crashing
  • Provides proper cleanup via removeListener

This is a secure and maintainable pattern for IPC event handling.

src/__tests__/lib/ipcSchemas.test.ts (1)

1-444: Excellent comprehensive test coverage.

This test suite provides thorough validation coverage for all IPC schemas:

  • Tests both valid and invalid inputs
  • Verifies boundary conditions (min/max lengths, array sizes)
  • Confirms error messages are user-friendly
  • Covers optional vs required field handling
  • Tests undefined vs null distinctions (important for Zod)

The functional tests provide stronger guarantees than simple regex-based existence checks and will catch schema regressions early.

src/components/AddShare.tsx (3)

127-139: Strengthened name validation.

The updated validation correctly enforces the maximum name length using centralized VALIDATION_LIMITS.NAME_MAX, improving consistency and maintainability. Trimming the input before validation prevents whitespace-only names.


265-270: Improved password validation with maximum length.

Adding an upper bound (VALIDATION_LIMITS.PASSWORD_MAX) prevents potential issues with extremely long passwords that could impact performance or storage. The validation now properly enforces both minimum and maximum constraints.


404-415: Correct IPC pattern for relay planning.

Using window.electronAPI.computeRelayPlan to delegate relay planning to the main process is the right approach. The main process has access to Node.js APIs (environment variables, file system) while keeping the renderer isolated. Error handling correctly propagates failures with user-friendly messages.

src/__tests__/integration/computeRelayPlan.test.ts (1)

1-188: Comprehensive integration test coverage.

This test suite effectively validates the compute-relay-plan IPC handler from multiple angles:

  1. Static analysis verifies critical implementation details (env var fallback, input normalization, error handling)
  2. Client-side integration tests the renderer's interaction with the mocked IPC surface
  3. Response structure validates the RelayPlan shape matches the type definition
  4. Preload exposure confirms the API is properly exposed to the renderer

The combination of static and runtime testing provides strong coverage without requiring a full Electron environment. Based on learnings, this aligns with the project's testing strategy for IPC handlers.

src/lib/echoRelays.ts (6)

1-5: LGTM!

The imports are well-organized with Node.js core modules using the node: prefix, external package imports, and internal types using the @/ alias per coding guidelines.


19-34: LGTM!

The URL normalization logic correctly enforces secure WebSocket connections (wss://) by upgrading insecure protocols. The regex patterns and replacements are correct.


36-44: LGTM!

Good defensive coding with proper handling of environments where process may not exist.


69-90: LGTM!

Synchronous config file reading is acceptable here since it's called from the main process for small configuration files. Error handling appropriately returns undefined for missing files or parse errors.


92-106: LGTM!

The canonicalization logic correctly handles URL normalization with a sensible fallback for malformed URLs.


197-206: LGTM!

Excellent security measure ensuring at least one relay is always configured. The fallback chain with appropriate warnings and a final error throw prevents silent failures.

src/__tests__/integration/electron-security.test.ts (8)

1-18: LGTM!

Good integration test setup for verifying Electron security configurations. Reading source files to verify security patterns is a pragmatic approach for ensuring security settings aren't accidentally removed.


20-57: LGTM!

Comprehensive coverage of critical Electron security settings. These tests act as guardrails against accidentally disabling security features.


59-106: LGTM!

Good verification that the preload script follows Electron security best practices by using contextBridge and not exposing raw ipcRenderer.


109-170: LGTM!

Comprehensive CSP verification tests that ensure clickjacking prevention, safe script loading, and proper restrictions on various resource types.


172-195: LGTM!

Good enforcement of the secure IPC pattern. These tests ensure renderer code doesn't bypass the security boundary by directly importing Electron APIs.


197-286: LGTM!

Comprehensive verification that all IPC handlers use Zod schema validation. This ensures input validation isn't accidentally bypassed.


288-315: LGTM!

Good verification that error sanitization is properly implemented to prevent leaking sensitive file paths in logs.


317-370: LGTM!

Complete coverage of navigation security and file permission hardening. These tests ensure the app is protected against navigation attacks and files have restrictive permissions.

src/main.ts (6)

6-19: LGTM!

Clean imports with proper separation of concerns - importing computeRelayPlan for relay logic and IPC schemas for validation. Follows the coding guideline of importing third-party packages before internal modules.


57-74: LGTM!

The SimplePool shim is properly guarded with try-catch and uses a flag to prevent double-patching. Good compatibility fix for relay filter handling.


78-162: LGTM!

Well-structured echo monitoring with proper relay plan integration and robust callback handling that supports both old and new payload shapes from @frostr/igloo-core.


262-309: LGTM!

Excellent security hardening with:

  • Secure webPreferences (nodeIntegration: false, contextIsolation: true, sandbox: true)
  • Navigation protection blocking external URLs
  • Safe handling of new window requests via system browser

322-336: LGTM!

Proper Zod validation pattern with safeParse and sanitized error logging. Returns appropriate failure response on validation errors.


372-411: LGTM!

Well-implemented IPC handler with proper Zod validation, environment variable fallback for sandboxed renderer, and structured response format. Good error handling with sanitized logging.

src/lib/ipcSchemas.ts (7)

1-12: LGTM!

Well-structured module with clear documentation explaining the security rationale for input validation schemas.


13-17: LGTM!

Good constraints for share IDs - the character restriction prevents path traversal attacks while allowing common identifier formats.


19-23: LGTM!

Appropriate salt validation - 32 hex chars (16 bytes) minimum ensures cryptographic adequacy while max 128 prevents excessive allocation.


25-67: LGTM!

Comprehensive schema definitions with appropriate length limits for all fields. The SaveShareSchema properly handles nested optional structures including metadata and policy objects.


77-94: LGTM!

Good array limits (100 share credentials, 50 relays) to prevent DoS attacks via oversized payloads while still allowing reasonable operational capacity.


96-103: LGTM!

Standard pattern for deriving TypeScript types from Zod schemas using z.infer, enabling type-safe handler implementations.


9-11: Unit test coverage for IPC schemas is comprehensive and verified.

The test file src/__tests__/lib/ipcSchemas.test.ts exists with extensive coverage for all schemas (ShareIdSchema, HexSaltSchema, RelayUrlSchema, ShareCredentialSchema, GroupCredentialSchema, SaveShareSchema, RelayPlanArgsSchema, EchoStartArgsSchema, EchoStopArgsSchema). Each schema is tested with valid inputs, boundary cases, invalid inputs, and format validation, confirming the module's design goal of testing schemas directly with valid/invalid payloads.

Copy link
Copy Markdown
Contributor

@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: 1

🧹 Nitpick comments (8)
src/lib/signer-keepalive.ts (1)

74-74: LGTM! Clean removal of unused variable.

The removal of selfPubkey from the destructuring is correct, as the variable is never referenced in the function body. The refactored no-peer handling (lines 284-293) now explicitly manages health state instead of pinging self, eliminating the need for this field.

💡 Consider making selfPubkey optional in the interface

Since selfPubkey is not currently used, consider updating the KeepAliveConfig interface to make it optional, which would better communicate to callers that this field is not required:

 interface KeepAliveConfig {
   node: BifrostNode;
   groupCredential: string;
   shareCredential: string;
   relays: string[];
-  selfPubkey: string;
+  selfPubkey?: string;
   logger?: KeepAliveLogger;
   options?: Partial<KeepAliveOptions>;
 }

This change would clarify the API contract and prevent confusion about whether the field needs to be provided.

src/components/Recover.tsx (3)

18-20: Consider using an environment variable for debug flags.

While the security comment is helpful, debug flags can accidentally be committed as true. Consider using a pattern like:

const DEBUG_AUTO_POPULATE = import.meta.env.DEV && false;

This ensures debug code never runs in production builds.


190-200: Good security practices with room for improvement.

The NSEC handling follows good security patterns:

  • Masked display by default
  • Auto-clear after timeout
  • Explicit user action required to reveal

However, consider these enhancements:

  • Shorter auto-clear timeout: 60 seconds may be generous for such sensitive data. Consider 30 seconds or less.
  • DevTools warning: React state is inspectable via browser DevTools. Consider adding a warning about keeping DevTools closed during recovery.

718-811: LGTM! Comprehensive secure NSEC display.

The UI implementation balances security and usability well:

Security features:

  • Prominent warning with security best practices
  • Masked display by default
  • Explicit reveal action required
  • Manual clear option

UX features:

  • Visual feedback for all actions (copy success/error, reveal/hide)
  • Clear iconography with descriptive labels
  • Error messages with recovery instructions

Minor suggestion: The conditional className on line 758 could use the cn() utility for better readability:

className={cn(
  'flex-1 text-sm',
  copyError ? 'bg-red-600 hover:bg-red-700' : 'bg-blue-600 hover:bg-blue-700'
)}
src/preload.ts (1)

17-22: Consider more specific types for the API surface.

The getShares return type (Promise<unknown>) and saveShare parameter type (unknown) lose compile-time type safety for renderer code. While runtime validation occurs in the main process, explicit types here would catch errors at compile time and improve developer experience.

Consider using the actual types (e.g., Promise<IglooShare[]> for getShares, IglooShare for saveShare parameter) or document why unknown is necessary.

🔧 Example with explicit types
+import type { IglooShare } from '@/types';
+
 export interface ElectronAPI {
   // Share management
-  getShares: () => Promise<unknown>;
-  saveShare: (share: unknown) => Promise<boolean>;
+  getShares: () => Promise<IglooShare[]>;
+  saveShare: (share: IglooShare) => Promise<boolean>;
   deleteShare: (shareId: string) => Promise<boolean>;
src/main.ts (2)

25-44: Consider unit tests for the security-critical sanitization logic.

The sanitizeErrorForLog function uses complex regex patterns to sanitize file paths. Given its security importance and complexity, dedicated unit tests would help ensure correctness across different path formats and edge cases.

#!/bin/bash
# Check if sanitizeErrorForLog has test coverage
echo "=== Checking for sanitizeErrorForLog tests ==="
rg -n "sanitizeErrorForLog" src/__tests__/ -A 3 -B 3

133-162: Consider adding inline documentation for callback signature handling.

The handleCoreCallback function supports multiple callback signatures (3-arg tuple vs. single-arg payload) to maintain compatibility. While the implementation is correct, the complexity could be reduced with better inline documentation explaining which signature corresponds to which igloo-core version or use case.

📝 Example documentation
 function handleCoreCallback(
   arg1: number | EchoPayload,
   arg2?: string | Record<string, unknown>,
   arg3?: unknown
 ): void {
   try {
-    // Case 1: (subsetIndex: number, shareCredential: string, details?: { challenge?: string })
+    // Case 1: Legacy igloo-core signature (v0.1.x-v0.2.x)
+    // (subsetIndex: number, shareCredential: string, details?: { challenge?: string })
     if (typeof arg1 === 'number') {
       ...
     }
 
-    // Case 2: (payload: { shareIndex, shareCredential, challenge? })
+    // Case 2: Modern igloo-core signature (v0.3.x+)
+    // (payload: { shareIndex, shareCredential, challenge? })
     if (isEchoPayload(arg1)) {
       ...
     }
src/components/AddShare.tsx (1)

395-398: Consider moving LegacyDecodedGroup to types file.

The LegacyDecodedGroup type is defined inline here. Since it represents a shared IPC contract shape used for relay planning, consider moving it to src/types/index.ts alongside DecodedGroup for better discoverability and reusability.

♻️ Refactor to shared types file

In src/types/index.ts:

export type LegacyDecodedGroup = DecodedGroup & {
  relayUrls?: string[];
  relay_urls?: string[];
};

In this file:

+import type { LegacyDecodedGroup } from '@/types';
+
 const AddShare: React.FC<AddShareProps> = ({ onComplete, onCancel }) => {
   ...
   try {
     ...
-    type LegacyDecodedGroup = DecodedGroup & {
-      relayUrls?: string[];
-      relay_urls?: string[];
-    };
-
     const legacyGroup = decodedGroup as LegacyDecodedGroup;
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 83ad080 and f8fc4d2.

📒 Files selected for processing (5)
  • src/components/AddShare.tsx
  • src/components/Recover.tsx
  • src/lib/signer-keepalive.ts
  • src/main.ts
  • src/preload.ts
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Use strict TypeScript mode with explicit types for function parameters and returns
Prefer interfaces over types for defining object shapes in TypeScript
Use @/ path alias for imports instead of relative paths
Use camelCase for functions and variables
Use UPPER_SNAKE_CASE for constants

Files:

  • src/preload.ts
  • src/components/AddShare.tsx
  • src/lib/signer-keepalive.ts
  • src/components/Recover.tsx
  • src/main.ts
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.{ts,tsx}: All runtime code is TypeScript with two-space indentation and required semicolons
Import third-party packages before internal modules and use the @/ alias for local paths

Files:

  • src/preload.ts
  • src/components/AddShare.tsx
  • src/lib/signer-keepalive.ts
  • src/components/Recover.tsx
  • src/main.ts
src/components/[A-Z]*.tsx

📄 CodeRabbit inference engine (CLAUDE.md)

Use PascalCase for component files

Files:

  • src/components/AddShare.tsx
  • src/components/Recover.tsx
src/components/**/*.tsx

📄 CodeRabbit inference engine (CLAUDE.md)

src/components/**/*.tsx: Use Tailwind CSS utility classes in JSX and use cn() utility for conditional classes
Avoid inline styles unless conditionally computed
Use functional components with hooks instead of class components
Use ipcRenderer.invoke() in renderer process to call IPC handlers without direct file system access

Tailwind utility classes style JSX; reserve inline styles for dynamic values only

Files:

  • src/components/AddShare.tsx
  • src/components/Recover.tsx
src/{components,lib,types}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

UI components sit under src/components/, helpers in src/lib/, shared types in src/types/

Files:

  • src/components/AddShare.tsx
  • src/lib/signer-keepalive.ts
  • src/components/Recover.tsx
src/components/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

src/components/**/*.{ts,tsx}: Prefer functional React components; name them in PascalCase and helpers in camelCase
Components in src/components/ follow kebab-case filenames (e.g., share-list.tsx)

Files:

  • src/components/AddShare.tsx
  • src/components/Recover.tsx
src/main.ts

📄 CodeRabbit inference engine (CLAUDE.md)

src/main.ts: Register IPC handlers in main.ts using ipcMain.handle() for file system operations
Electron's main process uses CommonJS (require) while renderer uses ESM (import)

Main Electron process lives in src/main.ts; the renderer bootstraps from src/renderer.tsx

Files:

  • src/main.ts
🧠 Learnings (11)
📓 Common learnings
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T23:50:29.859Z
Learning: Applies to src/**/*ipc*.{ts,tsx} : Cover new IPC handlers with unit tests plus at least one scenario in `src/__tests__/integration/`
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/main.ts : Electron's main process uses CommonJS (require) while renderer uses ESM (import)

Applied to files:

  • src/preload.ts
  • src/components/AddShare.tsx
📚 Learning: 2026-01-02T23:50:29.859Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T23:50:29.859Z
Learning: Applies to src/main.ts : Main Electron process lives in `src/main.ts`; the renderer bootstraps from `src/renderer.tsx`

Applied to files:

  • src/preload.ts
  • src/components/AddShare.tsx
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/__tests__/**/*.test.{ts,tsx} : Mock Electron's ipcRenderer and app APIs in tests

Applied to files:

  • src/preload.ts
  • src/components/AddShare.tsx
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/__tests__/integration/**/*.test.{ts,tsx} : Test Electron IPC communication in __tests__/integration/ directory

Applied to files:

  • src/preload.ts
  • src/components/AddShare.tsx
  • src/main.ts
📚 Learning: 2026-01-02T23:50:29.859Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T23:50:29.859Z
Learning: Applies to src/**/*ipc*.{ts,tsx} : Cover new IPC handlers with unit tests plus at least one scenario in `src/__tests__/integration/`

Applied to files:

  • src/preload.ts
  • src/components/AddShare.tsx
  • src/main.ts
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/main.ts : Register IPC handlers in main.ts using ipcMain.handle() for file system operations

Applied to files:

  • src/preload.ts
  • src/main.ts
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/components/**/*.tsx : Use ipcRenderer.invoke() in renderer process to call IPC handlers without direct file system access

Applied to files:

  • src/preload.ts
  • src/components/AddShare.tsx
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/lib/shareManager.ts : Never store plaintext share data; always encrypt with user passwords

Applied to files:

  • src/components/AddShare.tsx
  • src/components/Recover.tsx
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Do not implement cryptographic logic in the desktop app; delegate all crypto operations to frostr/igloo-core

Applied to files:

  • src/components/AddShare.tsx
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/lib/shareManager.ts : Store shares in <appData>/igloo/shares/ directory using the defined JSON schema

Applied to files:

  • src/components/AddShare.tsx
  • src/components/Recover.tsx
  • src/main.ts
🧬 Code graph analysis (4)
src/preload.ts (1)
src/types/index.ts (1)
  • RelayPlan (191-198)
src/components/AddShare.tsx (2)
src/lib/validation.ts (2)
  • VALIDATION_LIMITS (4-15)
  • sanitizeUserError (432-458)
src/types/index.ts (1)
  • DecodedGroup (9-19)
src/components/Recover.tsx (2)
src/lib/validation.ts (1)
  • VALIDATION_LIMITS (4-15)
src/components/ui/button.tsx (1)
  • Button (56-56)
src/main.ts (2)
src/lib/echoRelays.ts (1)
  • computeRelayPlan (143-219)
src/lib/ipcSchemas.ts (5)
  • SaveShareSchema (39-67)
  • ShareIdSchema (14-17)
  • RelayPlanArgsSchema (70-75)
  • EchoStartArgsSchema (78-87)
  • EchoStopArgsSchema (90-94)
🔇 Additional comments (21)
src/components/Recover.tsx (10)

7-8: LGTM!

Clean addition of icon imports and centralized validation constants to support the secure NSEC display features.


184-187: LGTM!

Good improvement to support flexible result messages. Using null as the initial state is more idiomatic than an empty string.


328-344: LGTM! Excellent defensive validation.

The threshold bounds check prevents potential edge cases where an invalid threshold could break the UI. Using VALIDATION_LIMITS ensures consistency across the codebase.

The silent return is acceptable here since invalid thresholds should never occur during normal use (they're validated when the group credential is decoded).


365-365: LGTM!

More explicit validation check improves code clarity without changing behavior.


427-445: LGTM!

Comprehensive cleanup of NSEC state and timeouts. The useCallback with empty dependencies is correct since all setters are stable.


447-474: LGTM! Excellent error handling.

The clipboard copy implementation is robust:

  • Proper timeout cleanup prevents multiple concurrent timers
  • Resets success state on error to avoid contradictory UI
  • User-friendly error messages with fallback instructions
  • Auto-clears feedback states for clean UX

476-479: LGTM!

Simple, correct state toggle with proper useCallback usage.


481-492: LGTM! Proper cleanup implementation.

The timeout cleanup on unmount is correct. The eslint-disable comment is justified here since refs don't need to be in the dependency array, and accessing .current in cleanup is the intended pattern.


502-502: LGTM!

Consistent with the validation improvement at line 365.


553-594: LGTM! Secure NSEC recovery flow.

The implementation properly manages the NSEC lifecycle:

  1. Clears any previous NSEC before storing the new one
  2. Resets all UI state for clean display
  3. Sets up auto-clear timeout for security
  4. Updates the user when auto-clear occurs

The automatic message update after 60 seconds helps users understand why the NSEC disappeared.

src/preload.ts (2)

57-85: LGTM: Runtime type validation.

The type guards properly validate IPC payloads with appropriate handling of optional fields (shareCredential, challenge). This prevents malformed data from reaching renderer callbacks.


88-154: LGTM: Secure IPC bridge with defensive callback handling.

The implementation properly:

  • Validates callbacks are functions before registering handlers (lines 118, 138)
  • Validates IPC payloads before invoking callbacks (lines 123, 143)
  • Returns cleanup functions for proper resource management
  • Uses satisfies ElectronAPI to ensure type compliance
src/main.ts (5)

184-213: LGTM: Robust relay canonicalization with deduplication.

The relay target canonicalization:

  • Uses URL parsing with regex fallback for malformed URLs
  • Normalizes protocol, hostname, and path components
  • Deduplicates relay sets to prevent redundant listeners

This prevents cross-contamination between listener instances.


266-309: LGTM: Comprehensive Electron security hardening.

The security configuration properly:

  • Disables Node.js integration in renderer (line 268)
  • Enables context isolation (line 269)
  • Enables Chromium sandbox (line 270)
  • Blocks navigation to external URLs (lines 291-296)
  • Opens external links in system browser, not new Electron windows (lines 301-307)

These settings align with Electron security best practices.


322-370: LGTM: Input validation and error sanitization in IPC handlers.

The IPC handlers properly:

  • Validate inputs with Zod schemas before processing (lines 325, 341, 357)
  • Log validation failures with specific issues (lines 328, 344, 360)
  • Sanitize errors before logging (lines 333, 349, 367)
  • Return appropriate responses for validation failures

This pattern provides defense-in-depth against malicious or malformed inputs.


413-482: LGTM: echo-start handler with validation and cleanup.

The handler properly:

  • Validates inputs with EchoStartArgsSchema (line 415)
  • Cleans up existing listeners before creating new ones (lines 425-434)
  • Normalizes and filters share credentials (lines 437-440)
  • Registers cleanup on sender destruction (lines 459-470)
  • Sanitizes errors in logs (line 479)

372-411: Add unit tests for compute-relay-plan IPC handler

Integration tests for the handler exist (src/__tests__/integration/computeRelayPlan.test.ts), but unit tests are missing. The learning requirement specifies both unit tests and integration test scenarios.

The handler implementation is solid with proper validation via RelayPlanArgsSchema, input normalization, env var fallback to process.env.IGLOO_RELAY, and error sanitization. Add unit tests covering:

  • Input validation success/failure paths
  • Each field normalization (trim, filter empty)
  • Env var fallback logic
  • Error handling
⛔ Skipped due to learnings
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T23:50:29.859Z
Learning: Applies to src/**/*ipc*.{ts,tsx} : Cover new IPC handlers with unit tests plus at least one scenario in `src/__tests__/integration/`
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/__tests__/integration/**/*.test.{ts,tsx} : Test Electron IPC communication in __tests__/integration/ directory
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/components/**/*.tsx : Use ipcRenderer.invoke() in renderer process to call IPC handlers without direct file system access
src/components/AddShare.tsx (4)

125-154: LGTM: Share name validation with proper limits.

The validation correctly:

  • Trims input before checking (line 127)
  • Enforces required field (lines 129-133)
  • Applies max length from VALIDATION_LIMITS.NAME_MAX (lines 135-139)
  • Prevents duplicates using normalized names (lines 141-147)

196-200: LGTM: Sanitized error messages for decode failures.

Using sanitizeUserError for group and share decode errors (lines 198, 249) prevents exposing internal implementation details to users while providing helpful feedback.

Also applies to: 246-251


259-274: LGTM: Password validation with updated limits.

Password validation properly enforces:

  • Minimum length via VALIDATION_LIMITS.PASSWORD_MIN (line 265)
  • Maximum length via VALIDATION_LIMITS.PASSWORD_MAX (line 268)
  • Clear error messages for each constraint

404-421: LGTM: Relay plan computation via secure IPC bridge.

The implementation correctly:

  • Computes relay plan via window.electronAPI.computeRelayPlan (lines 404-409)
  • Passes group credential and decoded group for IPC serialization (lines 405-408)
  • Handles failures by throwing with the provided message (lines 411-413)
  • Uses computed relays for echo send with timeout (lines 417-419)

The environment variable access limitation (line 420 comment) is accurate since the renderer process cannot access process.env due to contextIsolation: true.

@AustinKelsay
Copy link
Copy Markdown
Member Author

@CodeRabbit full review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Jan 8, 2026

✅ Actions performed

Full review triggered.

Copy link
Copy Markdown
Contributor

@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: 3

🤖 Fix all issues with AI agents
In @SECURITY_AUDIT_2026-01-06.md:
- Line 1031: Update the stale "3 critical issues requiring attention (#3, #4, #5
- React input validation)" note at line content and replace it with an accurate
statement that reflects the remediation status (e.g., "all 5 critical issues
have been fixed" or remove the parenthetical list entirely); ensure the
"Remaining Work" summary and any references to critical issue numbers are
consistent with the remediation section so the document no longer reports
resolved critical issues as open.

In @src/lib/ipcSchemas.ts:
- Around line 25-26: RelayUrlSchema currently only checks length; you must
enforce URL format and SSRF protection by either adding .refine(isValidRelayUrl)
to RelayUrlSchema so parsing validates each relay, or explicitly calling
isValidRelayUrl (and/or formatRelayUrl) for each relay after schema parsing in
the compute-relay-plan handler before passing to computeRelayPlan(); also remove
the unused relays field from EchoStartArgsSchema (and the echo-start handler) if
it’s truly dead code, and ensure normalizeRelayUrl remains only for protocol
normalization and not relied on for security checks.

In @src/lib/validation.ts:
- Around line 410-411: The current normalization uses trimmed.split(' share
')[0], which naively chops at any " share " occurrence and will incorrectly
shorten names like "My share backup"; update the logic that assigns normalized
(based on trimmed) to only strip a specific trailing suffix pattern instead of
splitting anywhere—e.g., remove a trailing " share" or " share backup"
(case-insensitive) only when it appears at the end, then re-trim; locate the
assignment to normalized and replace the split-based approach with a
suffix-aware regex or string-endsWith check operating on trimmed.
🧹 Nitpick comments (14)
src/__tests__/lib/igloo-core-integration.test.ts (1)

1-4: LGTM! Consider adding brief JSDoc comments.

The helper functions correctly generate deterministic hex strings with appropriate lengths (64 chars for scalars, 66 chars for compressed points). The implementation is clean and serves the testing purpose well.

📝 Optional: Add JSDoc for clarity
+// Helper to generate realistic 64-char hex strings for scalar values (e.g., secret keys, nonces)
 const toScalarHex = (seed: number): string => seed.toString(16).padStart(64, '0');
+// Helper to generate realistic 66-char hex strings for public points (compressed EC point format)
 const toPointHex = (seed: number): string => '02' + seed.toString(16).padStart(64, '0');
src/__tests__/integration/userInputValidation.test.ts (1)

2-3: Consider using @/ path alias for imports.

Per coding guidelines, prefer @/ path alias over relative paths for internal imports.

Suggested change
-import { validatePassword, formatRelayUrl, isValidRelayUrl, validateSalt, isValidSalt } from '../../lib/validation';
-import { sanitizeShareFilename, isFilenameSafe, FILESYSTEM_LIMITS } from '../../lib/filesystem';
+import { validatePassword, formatRelayUrl, isValidRelayUrl, validateSalt, isValidSalt } from '@/lib/validation';
+import { sanitizeShareFilename, isFilenameSafe, FILESYSTEM_LIMITS } from '@/lib/filesystem';
src/__tests__/workflows/share-lifecycle.test.ts (1)

5-6: Consider importing toScalarHex from shared mock.

This helper duplicates the one in bifrost.mock.ts. Import from the shared mock to maintain DRY principle.

Suggested change
+import { toScalarHex } from '../__mocks__/bifrost.mock';
+
-// Helper to generate realistic 64-char hex strings for scalar values
-const toScalarHex = (seed: number): string => seed.toString(16).padStart(64, '0');

Note: This requires exporting toScalarHex from bifrost.mock.ts (currently it's a file-scoped const).

src/lib/ipcSchemas.ts (1)

70-75: decodedGroup accepts any object structure.

z.record(z.unknown()) is very permissive. If decodedGroup has a known structure, consider defining a stricter schema to catch malformed inputs at the IPC boundary.

Consider typing decodedGroup more strictly

If the decoded group has a known shape:

const DecodedGroupSchema = z.object({
  threshold: z.number().int().min(1),
  commits: z.array(z.object({
    idx: z.number().int(),
    pubkey: z.string(),
    hidden_pn: z.string(),
    binder_pn: z.string(),
  })),
  group_pk: z.string(),
}).optional();
src/__tests__/lib/validation.test.ts (1)

8-16: Import uses relative path instead of @/ alias.

Per coding guidelines, prefer @/ path alias for imports instead of relative paths.

Suggested import style
-import {
-  VALIDATION_LIMITS,
-  validatePassword,
-  validatePositiveInteger,
-  validateShareName,
-  sanitizeUserError,
-  validatePasswordLength,
-  formatRelayUrl,
-} from '../../lib/validation';
+import {
+  VALIDATION_LIMITS,
+  validatePassword,
+  validatePositiveInteger,
+  validateShareName,
+  sanitizeUserError,
+  validatePasswordLength,
+  formatRelayUrl,
+} from '@/lib/validation';
src/__tests__/lib/echoRelays.test.ts (1)

1-3: Import uses relative path instead of @/ alias.

Per coding guidelines, prefer @/ path alias for imports.

Suggested import style
-import { computeRelayPlan, normalizeRelayUrl } from '../../lib/echoRelays';
+import { computeRelayPlan, normalizeRelayUrl } from '@/lib/echoRelays';
src/__tests__/integration/computeRelayPlan.test.ts (1)

14-74: Static analysis tests provide good structural verification, but consider fragility.

Using regex to verify handler registration and schema usage is a pragmatic approach for integration tests. However, these tests may break with minor formatting changes. The tests do cover important aspects:

  • Handler registration pattern
  • Schema validation structure
  • Environment variable fallback
  • Input normalization
  • Error handling structure

Consider adding a comment noting these tests verify structural contracts and may need updates if implementation formatting changes significantly.

src/__tests__/components/Recover.test.tsx (1)

13-19: Clipboard mock setup is correct.

The mock enables testing copy-to-clipboard flows. Consider using jest.spyOn instead of Object.assign for easier restoration in case other tests need the real clipboard API.

Alternative clipboard mock approach
-// Mock clipboard API
-const mockClipboardWriteText = jest.fn().mockResolvedValue(undefined);
-Object.assign(navigator, {
-  clipboard: {
-    writeText: mockClipboardWriteText,
-  },
-});
+// Mock clipboard API
+const mockClipboardWriteText = jest.fn().mockResolvedValue(undefined);
+beforeAll(() => {
+  Object.defineProperty(navigator, 'clipboard', {
+    value: { writeText: mockClipboardWriteText },
+    configurable: true,
+  });
+});
src/lib/echoRelays.ts (2)

92-106: Consider URL parsing edge case.

The dedupeKey function handles URL parsing failures gracefully with a regex fallback. However, the fallback regex doesn't preserve query strings and fragments from non-standard URLs.

Minor: Include query/fragment in regex fallback
   } catch {
     const match = url.match(/^(wss?):\/\/([^/?#]+)(.*)$/i);
     if (match) {
-      return `${match[1].toLowerCase()}://${match[2].toLowerCase()}${match[3] ?? ''}`;
+      // match[3] captures path, query, and fragment
+      return `${match[1].toLowerCase()}://${match[2].toLowerCase()}${match[3] || ''}`;
     }
     return url;
   }

Note: The ?? '' and || '' are functionally equivalent here since match[3] will be either a string or undefined, not null. Current code is correct.


170-180: Duplicate dedupe function - consider consolidation.

There's a local dedupe function inside computeRelayPlan that has similar logic to normalizeList. While the inner dedupe operates on already-normalized strings (skipping the normalize step), this could be slightly confusing.

Consider extracting to a shared helper

The inner dedupe function could be extracted as dedupeNormalized to clarify it's for already-normalized URLs, or normalizeList could be enhanced to accept a skip-normalize flag.

src/components/Recover.tsx (1)

753-800: Minor: Button layout could use consistent flex-1.

The Copy button has flex-1 but Reveal and Clear don't, which may cause uneven button widths depending on content length. This is a minor styling consideration.

Optional: Consistent button widths
               <Button
                 type="button"
                 onClick={handleToggleNsecReveal}
                 variant="outline"
-                className="bg-gray-700 hover:bg-gray-600 border-gray-600 text-sm"
+                className="flex-1 bg-gray-700 hover:bg-gray-600 border-gray-600 text-sm"
               >
src/lib/validation.ts (1)

127-153: SSRF protection only handles IPv4 - consider IPv6.

The isPrivateOrReservedIp function only validates IPv4 addresses. IPv6 private/reserved ranges (e.g., ::1, fe80::, fc00::/7) are not blocked, which could allow SSRF bypasses via IPv6 addresses.

🛡️ Consider adding IPv6 protection
+function isPrivateOrReservedIpv6(ip: string): boolean {
+  const normalized = ip.toLowerCase();
+  // Loopback
+  if (normalized === '::1' || normalized === '0:0:0:0:0:0:0:1') return true;
+  // Link-local (fe80::/10)
+  if (normalized.startsWith('fe8') || normalized.startsWith('fe9') ||
+      normalized.startsWith('fea') || normalized.startsWith('feb')) return true;
+  // Unique local (fc00::/7)
+  if (normalized.startsWith('fc') || normalized.startsWith('fd')) return true;
+  // IPv4-mapped IPv6 (::ffff:x.x.x.x) - delegate to IPv4 check
+  const v4Mapped = normalized.match(/^::ffff:(\d+\.\d+\.\d+\.\d+)$/);
+  if (v4Mapped) return isPrivateOrReservedIp(v4Mapped[1]);
+  return false;
+}
src/__tests__/integration/electron-security.test.ts (1)

129-135: CSP unsafe-eval check could have false negatives.

The test only checks if scriptSrcMatch exists before verifying no unsafe-eval. If the regex doesn't match (e.g., due to formatting), the test silently passes without verification.

💡 Consider making the test more robust
   it('should NOT allow unsafe-eval in scripts', () => {
-    // Check that script-src doesn't include unsafe-eval
     const scriptSrcMatch = indexHtmlContent.match(/script-src[^;]*/);
-    if (scriptSrcMatch) {
-      expect(scriptSrcMatch[0]).not.toContain('unsafe-eval');
-    }
+    expect(scriptSrcMatch).not.toBeNull();
+    expect(scriptSrcMatch![0]).not.toContain('unsafe-eval');
   });
SECURITY_AUDIT_2026-01-06.md (1)

269-269: Minor grammar nit per static analysis.

Consider using "High-Severity" with a hyphen when used as a compound adjective before "Issues" for consistency.

-## High Severity Issues
+## High-Severity Issues
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1bb4086 and f8fc4d2.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (41)
  • CLAUDE.md
  • SECURITY_AUDIT_2026-01-06.md
  • index.html
  • package.json
  • src/__tests__/__mocks__/bifrost.mock.ts
  • src/__tests__/components/AddShare.test.tsx
  • src/__tests__/components/LoadShare.test.tsx
  • src/__tests__/components/Recover.test.tsx
  • src/__tests__/components/SaveShare.test.tsx
  • src/__tests__/components/Signer.test.tsx
  • src/__tests__/integration/clientShareManager.test.ts
  • src/__tests__/integration/computeRelayPlan.test.ts
  • src/__tests__/integration/electron-security.test.ts
  • src/__tests__/integration/userInputValidation.test.ts
  • src/__tests__/lib/echoRelays.test.ts
  • src/__tests__/lib/igloo-core-integration.test.ts
  • src/__tests__/lib/ipcSchemas.test.ts
  • src/__tests__/lib/shareManager.test.ts
  • src/__tests__/lib/validation.test.ts
  • src/__tests__/setup.ts
  • src/__tests__/workflows/keyset-creation.test.ts
  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/components/AddShare.tsx
  • src/components/Create.tsx
  • src/components/Keyset.tsx
  • src/components/LoadShare.tsx
  • src/components/Recover.tsx
  • src/components/SaveShare.tsx
  • src/components/Signer.tsx
  • src/lib/clientShareManager.ts
  • src/lib/echoRelays.ts
  • src/lib/ipcSchemas.ts
  • src/lib/shareManager.ts
  • src/lib/signer-keepalive.ts
  • src/lib/validation.ts
  • src/main.ts
  • src/preload.ts
  • src/types/index.ts
  • tsconfig.preload.json
  • tsconfig.test.json
  • webpack.config.cjs
🧰 Additional context used
📓 Path-based instructions (18)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Use strict TypeScript mode with explicit types for function parameters and returns
Prefer interfaces over types for defining object shapes in TypeScript
Use @/ path alias for imports instead of relative paths
Use camelCase for functions and variables
Use UPPER_SNAKE_CASE for constants

Files:

  • src/components/Signer.tsx
  • src/__tests__/lib/igloo-core-integration.test.ts
  • src/__tests__/components/SaveShare.test.tsx
  • src/components/Create.tsx
  • src/preload.ts
  • src/__tests__/components/AddShare.test.tsx
  • src/__tests__/lib/ipcSchemas.test.ts
  • src/__tests__/lib/shareManager.test.ts
  • src/__tests__/setup.ts
  • src/types/index.ts
  • src/lib/shareManager.ts
  • src/lib/signer-keepalive.ts
  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/__tests__/lib/echoRelays.test.ts
  • src/__tests__/lib/validation.test.ts
  • src/__tests__/components/Signer.test.tsx
  • src/__tests__/components/LoadShare.test.tsx
  • src/__tests__/components/Recover.test.tsx
  • src/components/AddShare.tsx
  • src/components/LoadShare.tsx
  • src/__tests__/integration/electron-security.test.ts
  • src/lib/echoRelays.ts
  • src/__tests__/integration/computeRelayPlan.test.ts
  • src/lib/validation.ts
  • src/main.ts
  • src/lib/ipcSchemas.ts
  • src/__tests__/integration/clientShareManager.test.ts
  • src/lib/clientShareManager.ts
  • src/__tests__/workflows/keyset-creation.test.ts
  • src/components/SaveShare.tsx
  • src/__tests__/__mocks__/bifrost.mock.ts
  • src/components/Keyset.tsx
  • src/components/Recover.tsx
  • src/__tests__/integration/userInputValidation.test.ts
src/components/[A-Z]*.tsx

📄 CodeRabbit inference engine (CLAUDE.md)

Use PascalCase for component files

Files:

  • src/components/Signer.tsx
  • src/components/Create.tsx
  • src/components/AddShare.tsx
  • src/components/LoadShare.tsx
  • src/components/SaveShare.tsx
  • src/components/Keyset.tsx
  • src/components/Recover.tsx
src/components/**/*.tsx

📄 CodeRabbit inference engine (CLAUDE.md)

src/components/**/*.tsx: Use Tailwind CSS utility classes in JSX and use cn() utility for conditional classes
Avoid inline styles unless conditionally computed
Use functional components with hooks instead of class components
Use ipcRenderer.invoke() in renderer process to call IPC handlers without direct file system access

Tailwind utility classes style JSX; reserve inline styles for dynamic values only

Files:

  • src/components/Signer.tsx
  • src/components/Create.tsx
  • src/components/AddShare.tsx
  • src/components/LoadShare.tsx
  • src/components/SaveShare.tsx
  • src/components/Keyset.tsx
  • src/components/Recover.tsx
src/{components,lib,types}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

UI components sit under src/components/, helpers in src/lib/, shared types in src/types/

Files:

  • src/components/Signer.tsx
  • src/components/Create.tsx
  • src/types/index.ts
  • src/lib/shareManager.ts
  • src/lib/signer-keepalive.ts
  • src/components/AddShare.tsx
  • src/components/LoadShare.tsx
  • src/lib/echoRelays.ts
  • src/lib/validation.ts
  • src/lib/ipcSchemas.ts
  • src/lib/clientShareManager.ts
  • src/components/SaveShare.tsx
  • src/components/Keyset.tsx
  • src/components/Recover.tsx
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.{ts,tsx}: All runtime code is TypeScript with two-space indentation and required semicolons
Import third-party packages before internal modules and use the @/ alias for local paths

Files:

  • src/components/Signer.tsx
  • src/__tests__/lib/igloo-core-integration.test.ts
  • src/__tests__/components/SaveShare.test.tsx
  • src/components/Create.tsx
  • src/preload.ts
  • src/__tests__/components/AddShare.test.tsx
  • src/__tests__/lib/ipcSchemas.test.ts
  • src/__tests__/lib/shareManager.test.ts
  • src/__tests__/setup.ts
  • src/types/index.ts
  • src/lib/shareManager.ts
  • src/lib/signer-keepalive.ts
  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/__tests__/lib/echoRelays.test.ts
  • src/__tests__/lib/validation.test.ts
  • src/__tests__/components/Signer.test.tsx
  • src/__tests__/components/LoadShare.test.tsx
  • src/__tests__/components/Recover.test.tsx
  • src/components/AddShare.tsx
  • src/components/LoadShare.tsx
  • src/__tests__/integration/electron-security.test.ts
  • src/lib/echoRelays.ts
  • src/__tests__/integration/computeRelayPlan.test.ts
  • src/lib/validation.ts
  • src/main.ts
  • src/lib/ipcSchemas.ts
  • src/__tests__/integration/clientShareManager.test.ts
  • src/lib/clientShareManager.ts
  • src/__tests__/workflows/keyset-creation.test.ts
  • src/components/SaveShare.tsx
  • src/__tests__/__mocks__/bifrost.mock.ts
  • src/components/Keyset.tsx
  • src/components/Recover.tsx
  • src/__tests__/integration/userInputValidation.test.ts
src/components/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

src/components/**/*.{ts,tsx}: Prefer functional React components; name them in PascalCase and helpers in camelCase
Components in src/components/ follow kebab-case filenames (e.g., share-list.tsx)

Files:

  • src/components/Signer.tsx
  • src/components/Create.tsx
  • src/components/AddShare.tsx
  • src/components/LoadShare.tsx
  • src/components/SaveShare.tsx
  • src/components/Keyset.tsx
  • src/components/Recover.tsx
src/__tests__/**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

src/__tests__/**/*.test.{ts,tsx}: Mock @frostr/igloo-core functions at the module level in tests to avoid ESM/Jest complications
Use jest.clearAllMocks() in beforeEach hooks to ensure test isolation
Mock Electron's ipcRenderer and app APIs in tests

Files:

  • src/__tests__/lib/igloo-core-integration.test.ts
  • src/__tests__/components/SaveShare.test.tsx
  • src/__tests__/components/AddShare.test.tsx
  • src/__tests__/lib/ipcSchemas.test.ts
  • src/__tests__/lib/shareManager.test.ts
  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/__tests__/lib/echoRelays.test.ts
  • src/__tests__/lib/validation.test.ts
  • src/__tests__/components/Signer.test.tsx
  • src/__tests__/components/LoadShare.test.tsx
  • src/__tests__/components/Recover.test.tsx
  • src/__tests__/integration/electron-security.test.ts
  • src/__tests__/integration/computeRelayPlan.test.ts
  • src/__tests__/integration/clientShareManager.test.ts
  • src/__tests__/workflows/keyset-creation.test.ts
  • src/__tests__/integration/userInputValidation.test.ts
src/__tests__/lib/**/*.test.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Test utility functions in tests/lib/ directory

Files:

  • src/__tests__/lib/igloo-core-integration.test.ts
  • src/__tests__/lib/ipcSchemas.test.ts
  • src/__tests__/lib/shareManager.test.ts
  • src/__tests__/lib/echoRelays.test.ts
  • src/__tests__/lib/validation.test.ts
src/__tests__/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Tests mirror runtime code under src/__tests__/ with integration/, performance/, and __mocks__/ subdirectories for feature-specific coverage

Files:

  • src/__tests__/lib/igloo-core-integration.test.ts
  • src/__tests__/components/SaveShare.test.tsx
  • src/__tests__/components/AddShare.test.tsx
  • src/__tests__/lib/ipcSchemas.test.ts
  • src/__tests__/lib/shareManager.test.ts
  • src/__tests__/setup.ts
  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/__tests__/lib/echoRelays.test.ts
  • src/__tests__/lib/validation.test.ts
  • src/__tests__/components/Signer.test.tsx
  • src/__tests__/components/LoadShare.test.tsx
  • src/__tests__/components/Recover.test.tsx
  • src/__tests__/integration/electron-security.test.ts
  • src/__tests__/integration/computeRelayPlan.test.ts
  • src/__tests__/integration/clientShareManager.test.ts
  • src/__tests__/workflows/keyset-creation.test.ts
  • src/__tests__/__mocks__/bifrost.mock.ts
  • src/__tests__/integration/userInputValidation.test.ts
src/**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Jest with Testing Library powers renderer specs; place new tests beside features as <subject>.test.tsx

Files:

  • src/__tests__/lib/igloo-core-integration.test.ts
  • src/__tests__/components/SaveShare.test.tsx
  • src/__tests__/components/AddShare.test.tsx
  • src/__tests__/lib/ipcSchemas.test.ts
  • src/__tests__/lib/shareManager.test.ts
  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/__tests__/lib/echoRelays.test.ts
  • src/__tests__/lib/validation.test.ts
  • src/__tests__/components/Signer.test.tsx
  • src/__tests__/components/LoadShare.test.tsx
  • src/__tests__/components/Recover.test.tsx
  • src/__tests__/integration/electron-security.test.ts
  • src/__tests__/integration/computeRelayPlan.test.ts
  • src/__tests__/integration/clientShareManager.test.ts
  • src/__tests__/workflows/keyset-creation.test.ts
  • src/__tests__/integration/userInputValidation.test.ts
src/__tests__/components/**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Test React component behavior in tests/components/ directory

Files:

  • src/__tests__/components/SaveShare.test.tsx
  • src/__tests__/components/AddShare.test.tsx
  • src/__tests__/components/Signer.test.tsx
  • src/__tests__/components/LoadShare.test.tsx
  • src/__tests__/components/Recover.test.tsx
src/**/*ipc*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Cover new IPC handlers with unit tests plus at least one scenario in src/__tests__/integration/

Files:

  • src/__tests__/lib/ipcSchemas.test.ts
  • src/lib/ipcSchemas.ts
src/__tests__/{setup.ts,__mocks__/**}

📄 CodeRabbit inference engine (AGENTS.md)

Register shared mocks in src/__tests__/setup.ts and reuse fixtures from src/__tests__/__mocks__/

Files:

  • src/__tests__/setup.ts
  • src/__tests__/__mocks__/bifrost.mock.ts
src/lib/shareManager.ts

📄 CodeRabbit inference engine (CLAUDE.md)

src/lib/shareManager.ts: Never store plaintext share data; always encrypt with user passwords
Store shares in /igloo/shares/ directory using the defined JSON schema

Files:

  • src/lib/shareManager.ts
src/__tests__/workflows/**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Test end-to-end user flows in tests/workflows/ directory

Files:

  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/__tests__/workflows/keyset-creation.test.ts
src/__tests__/integration/**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Test Electron IPC communication in tests/integration/ directory

Files:

  • src/__tests__/integration/electron-security.test.ts
  • src/__tests__/integration/computeRelayPlan.test.ts
  • src/__tests__/integration/clientShareManager.test.ts
  • src/__tests__/integration/userInputValidation.test.ts
src/main.ts

📄 CodeRabbit inference engine (CLAUDE.md)

src/main.ts: Register IPC handlers in main.ts using ipcMain.handle() for file system operations
Electron's main process uses CommonJS (require) while renderer uses ESM (import)

Main Electron process lives in src/main.ts; the renderer bootstraps from src/renderer.tsx

Files:

  • src/main.ts
src/__tests__/__mocks__/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Place shared mock implementations in tests/mocks/ for use across test files

Files:

  • src/__tests__/__mocks__/bifrost.mock.ts
🧠 Learnings (28)
📓 Common learnings
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T23:50:29.859Z
Learning: Applies to src/**/*ipc*.{ts,tsx} : Cover new IPC handlers with unit tests plus at least one scenario in `src/__tests__/integration/`
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Do not implement cryptographic logic in the desktop app; delegate all crypto operations to frostr/igloo-core

Applied to files:

  • src/components/Signer.tsx
  • src/components/AddShare.tsx
  • CLAUDE.md
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/__tests__/**/*.test.{ts,tsx} : Mock frostr/igloo-core functions at the module level in tests to avoid ESM/Jest complications

Applied to files:

  • src/__tests__/lib/igloo-core-integration.test.ts
  • src/preload.ts
  • src/__tests__/components/AddShare.test.tsx
  • src/__tests__/lib/shareManager.test.ts
  • src/__tests__/setup.ts
  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/__tests__/lib/echoRelays.test.ts
  • src/__tests__/components/Signer.test.tsx
  • src/__tests__/components/Recover.test.tsx
  • package.json
  • tsconfig.test.json
  • src/__tests__/integration/electron-security.test.ts
  • src/__tests__/integration/clientShareManager.test.ts
  • src/__tests__/workflows/keyset-creation.test.ts
  • src/__tests__/__mocks__/bifrost.mock.ts
📚 Learning: 2026-01-02T23:50:29.859Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T23:50:29.859Z
Learning: Applies to src/**/*ipc*.{ts,tsx} : Cover new IPC handlers with unit tests plus at least one scenario in `src/__tests__/integration/`

Applied to files:

  • src/__tests__/lib/igloo-core-integration.test.ts
  • src/__tests__/components/SaveShare.test.tsx
  • src/preload.ts
  • src/__tests__/components/AddShare.test.tsx
  • src/__tests__/lib/ipcSchemas.test.ts
  • src/__tests__/lib/shareManager.test.ts
  • src/__tests__/setup.ts
  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/__tests__/lib/echoRelays.test.ts
  • src/__tests__/lib/validation.test.ts
  • src/__tests__/components/Signer.test.tsx
  • src/__tests__/components/LoadShare.test.tsx
  • src/__tests__/components/Recover.test.tsx
  • src/components/AddShare.tsx
  • src/__tests__/integration/electron-security.test.ts
  • src/__tests__/integration/computeRelayPlan.test.ts
  • src/main.ts
  • SECURITY_AUDIT_2026-01-06.md
  • src/lib/ipcSchemas.ts
  • src/__tests__/integration/clientShareManager.test.ts
  • src/__tests__/integration/userInputValidation.test.ts
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/__tests__/lib/**/*.test.ts : Test utility functions in __tests__/lib/ directory

Applied to files:

  • src/__tests__/lib/igloo-core-integration.test.ts
  • src/__tests__/components/SaveShare.test.tsx
  • src/preload.ts
  • src/__tests__/lib/ipcSchemas.test.ts
  • src/__tests__/lib/shareManager.test.ts
  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/__tests__/lib/echoRelays.test.ts
  • src/__tests__/lib/validation.test.ts
  • src/__tests__/components/Signer.test.tsx
  • src/__tests__/components/LoadShare.test.tsx
  • src/__tests__/components/Recover.test.tsx
  • tsconfig.test.json
  • src/__tests__/integration/electron-security.test.ts
  • CLAUDE.md
  • src/__tests__/integration/computeRelayPlan.test.ts
  • src/__tests__/workflows/keyset-creation.test.ts
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/__tests__/__mocks__/**/*.ts : Place shared mock implementations in __tests__/__mocks__/ for use across test files

Applied to files:

  • src/__tests__/lib/igloo-core-integration.test.ts
  • src/__tests__/components/SaveShare.test.tsx
  • src/preload.ts
  • src/__tests__/components/AddShare.test.tsx
  • src/__tests__/lib/shareManager.test.ts
  • src/__tests__/setup.ts
  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/__tests__/lib/echoRelays.test.ts
  • tsconfig.test.json
  • src/__tests__/integration/clientShareManager.test.ts
  • src/__tests__/workflows/keyset-creation.test.ts
  • src/__tests__/__mocks__/bifrost.mock.ts
📚 Learning: 2026-01-02T23:50:29.859Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T23:50:29.859Z
Learning: Applies to src/__tests__/{setup.ts,__mocks__/**} : Register shared mocks in `src/__tests__/setup.ts` and reuse fixtures from `src/__tests__/__mocks__/`

Applied to files:

  • src/__tests__/lib/igloo-core-integration.test.ts
  • src/__tests__/components/SaveShare.test.tsx
  • src/preload.ts
  • src/__tests__/components/AddShare.test.tsx
  • src/__tests__/setup.ts
  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/__tests__/lib/echoRelays.test.ts
  • src/__tests__/components/Signer.test.tsx
  • src/__tests__/components/Recover.test.tsx
  • src/__tests__/integration/clientShareManager.test.ts
  • src/__tests__/workflows/keyset-creation.test.ts
  • src/__tests__/__mocks__/bifrost.mock.ts
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/lib/shareManager.ts : Never store plaintext share data; always encrypt with user passwords

Applied to files:

  • src/__tests__/components/SaveShare.test.tsx
  • src/__tests__/components/AddShare.test.tsx
  • src/__tests__/lib/shareManager.test.ts
  • src/lib/shareManager.ts
  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/__tests__/components/LoadShare.test.tsx
  • src/components/AddShare.tsx
  • src/components/LoadShare.tsx
  • CLAUDE.md
  • SECURITY_AUDIT_2026-01-06.md
  • src/__tests__/integration/clientShareManager.test.ts
  • src/lib/clientShareManager.ts
  • src/__tests__/workflows/keyset-creation.test.ts
  • src/components/SaveShare.tsx
  • src/__tests__/__mocks__/bifrost.mock.ts
  • src/components/Keyset.tsx
  • src/components/Recover.tsx
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/__tests__/components/**/*.test.{ts,tsx} : Test React component behavior in __tests__/components/ directory

Applied to files:

  • src/__tests__/components/SaveShare.test.tsx
  • src/__tests__/components/AddShare.test.tsx
  • src/__tests__/lib/shareManager.test.ts
  • src/__tests__/lib/echoRelays.test.ts
  • src/__tests__/components/LoadShare.test.tsx
  • src/__tests__/components/Recover.test.tsx
  • tsconfig.test.json
  • src/__tests__/integration/electron-security.test.ts
📚 Learning: 2026-01-02T23:50:29.859Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T23:50:29.859Z
Learning: Applies to src/__tests__/**/*.{ts,tsx} : Tests mirror runtime code under `src/__tests__/` with `integration/`, `performance/`, and `__mocks__/` subdirectories for feature-specific coverage

Applied to files:

  • src/__tests__/components/SaveShare.test.tsx
  • src/preload.ts
  • src/__tests__/components/AddShare.test.tsx
  • src/__tests__/lib/ipcSchemas.test.ts
  • src/__tests__/lib/shareManager.test.ts
  • src/__tests__/setup.ts
  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/__tests__/lib/echoRelays.test.ts
  • src/__tests__/lib/validation.test.ts
  • src/__tests__/components/Signer.test.tsx
  • src/__tests__/components/LoadShare.test.tsx
  • src/__tests__/components/Recover.test.tsx
  • tsconfig.test.json
  • src/__tests__/integration/electron-security.test.ts
  • src/__tests__/integration/computeRelayPlan.test.ts
  • src/__tests__/integration/clientShareManager.test.ts
📚 Learning: 2026-01-02T23:50:29.859Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T23:50:29.859Z
Learning: Applies to src/**/*.{ts,tsx} : Import third-party packages before internal modules and use the `@/` alias for local paths

Applied to files:

  • tsconfig.preload.json
  • tsconfig.test.json
  • CLAUDE.md
  • webpack.config.cjs
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/main.ts : Electron's main process uses CommonJS (require) while renderer uses ESM (import)

Applied to files:

  • src/preload.ts
  • src/__tests__/setup.ts
  • src/components/AddShare.tsx
  • package.json
  • src/__tests__/integration/electron-security.test.ts
  • CLAUDE.md
  • src/main.ts
  • webpack.config.cjs
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/__tests__/**/*.test.{ts,tsx} : Mock Electron's ipcRenderer and app APIs in tests

Applied to files:

  • src/preload.ts
  • src/__tests__/components/AddShare.test.tsx
  • src/__tests__/lib/ipcSchemas.test.ts
  • src/__tests__/setup.ts
  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/__tests__/components/Signer.test.tsx
  • src/__tests__/components/Recover.test.tsx
  • src/__tests__/integration/electron-security.test.ts
  • src/__tests__/integration/computeRelayPlan.test.ts
  • src/__tests__/integration/clientShareManager.test.ts
  • src/lib/clientShareManager.ts
  • webpack.config.cjs
📚 Learning: 2026-01-02T23:50:29.859Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T23:50:29.859Z
Learning: Applies to src/main.ts : Main Electron process lives in `src/main.ts`; the renderer bootstraps from `src/renderer.tsx`

Applied to files:

  • src/preload.ts
  • src/__tests__/setup.ts
  • src/components/AddShare.tsx
  • package.json
  • CLAUDE.md
  • src/main.ts
  • webpack.config.cjs
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/__tests__/integration/**/*.test.{ts,tsx} : Test Electron IPC communication in __tests__/integration/ directory

Applied to files:

  • src/preload.ts
  • src/__tests__/components/AddShare.test.tsx
  • src/__tests__/lib/ipcSchemas.test.ts
  • src/__tests__/lib/shareManager.test.ts
  • src/__tests__/setup.ts
  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/__tests__/lib/echoRelays.test.ts
  • src/__tests__/lib/validation.test.ts
  • src/__tests__/components/LoadShare.test.tsx
  • src/__tests__/components/Recover.test.tsx
  • src/components/AddShare.tsx
  • src/__tests__/integration/electron-security.test.ts
  • CLAUDE.md
  • src/__tests__/integration/computeRelayPlan.test.ts
  • src/main.ts
  • src/lib/ipcSchemas.ts
  • src/__tests__/integration/clientShareManager.test.ts
  • src/lib/clientShareManager.ts
  • src/__tests__/integration/userInputValidation.test.ts
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/main.ts : Register IPC handlers in main.ts using ipcMain.handle() for file system operations

Applied to files:

  • src/preload.ts
  • src/__tests__/integration/electron-security.test.ts
  • src/__tests__/integration/computeRelayPlan.test.ts
  • src/main.ts
  • src/lib/clientShareManager.ts
  • src/components/Keyset.tsx
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/components/**/*.tsx : Use ipcRenderer.invoke() in renderer process to call IPC handlers without direct file system access

Applied to files:

  • src/preload.ts
  • src/__tests__/setup.ts
  • src/components/AddShare.tsx
  • src/__tests__/integration/electron-security.test.ts
  • src/__tests__/integration/computeRelayPlan.test.ts
  • src/__tests__/integration/clientShareManager.test.ts
  • src/lib/clientShareManager.ts
  • src/components/Keyset.tsx
📚 Learning: 2026-01-02T23:50:29.859Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T23:50:29.859Z
Learning: Debug flaky Electron tests with `npm test -- --runInBand` to serialize execution

Applied to files:

  • src/preload.ts
  • src/__tests__/setup.ts
  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/__tests__/integration/electron-security.test.ts
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/__tests__/**/*.test.{ts,tsx} : Use jest.clearAllMocks() in beforeEach hooks to ensure test isolation

Applied to files:

  • src/__tests__/components/AddShare.test.tsx
  • src/__tests__/setup.ts
  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/__tests__/components/Recover.test.tsx
  • tsconfig.test.json
  • src/__tests__/integration/clientShareManager.test.ts
  • src/__tests__/workflows/keyset-creation.test.ts
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/__tests__/workflows/**/*.test.{ts,tsx} : Test end-to-end user flows in __tests__/workflows/ directory

Applied to files:

  • src/__tests__/components/AddShare.test.tsx
  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/__tests__/lib/echoRelays.test.ts
  • src/__tests__/integration/electron-security.test.ts
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/lib/shareManager.ts : Store shares in <appData>/igloo/shares/ directory using the defined JSON schema

Applied to files:

  • src/__tests__/lib/ipcSchemas.test.ts
  • src/__tests__/lib/shareManager.test.ts
  • src/lib/shareManager.ts
  • src/__tests__/workflows/share-lifecycle.test.ts
  • src/components/AddShare.tsx
  • CLAUDE.md
  • src/main.ts
  • src/lib/ipcSchemas.ts
  • src/__tests__/integration/clientShareManager.test.ts
  • src/lib/clientShareManager.ts
  • src/components/Recover.tsx
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to src/lib/encryption.ts : Use PBKDF2 with 600,000 iterations for encrypting share files

Applied to files:

  • src/lib/shareManager.ts
  • src/components/LoadShare.tsx
  • src/components/SaveShare.tsx
  • src/__tests__/__mocks__/bifrost.mock.ts
📚 Learning: 2026-01-02T23:50:29.859Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T23:50:29.859Z
Learning: Applies to src/**/*.test.{ts,tsx} : Jest with Testing Library powers renderer specs; place new tests beside features as `<subject>.test.tsx`

Applied to files:

  • src/__tests__/lib/echoRelays.test.ts
  • src/__tests__/lib/validation.test.ts
  • src/__tests__/components/Signer.test.tsx
  • src/__tests__/components/Recover.test.tsx
  • tsconfig.test.json
  • src/__tests__/integration/electron-security.test.ts
  • src/__tests__/integration/computeRelayPlan.test.ts
📚 Learning: 2026-01-02T23:50:29.859Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T23:50:29.859Z
Learning: PRs should describe the change set, include screenshots or recordings for UI tweaks, and list run commands (`npm test`, `npm run lint`)

Applied to files:

  • package.json
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Applies to **/*.{ts,tsx} : Use @/ path alias for imports instead of relative paths

Applied to files:

  • tsconfig.test.json
  • webpack.config.cjs
📚 Learning: 2026-01-02T23:50:29.859Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T23:50:29.859Z
Learning: Applies to src/{components,lib,types}/**/*.{ts,tsx} : UI components sit under `src/components/`, helpers in `src/lib/`, shared types in `src/types/`

Applied to files:

  • tsconfig.test.json
  • CLAUDE.md
📚 Learning: 2026-01-02T23:50:29.859Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T23:50:29.859Z
Learning: Applies to src/**/*.{ts,tsx} : All runtime code is TypeScript with two-space indentation and required semicolons

Applied to files:

  • tsconfig.test.json
📚 Learning: 2026-01-02T23:50:16.045Z
Learnt from: CR
Repo: FROSTR-ORG/igloo-desktop PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-02T23:50:16.045Z
Learning: Use props and callbacks for component communication instead of external state libraries like Redux

Applied to files:

  • CLAUDE.md
🧬 Code graph analysis (15)
src/__tests__/components/SaveShare.test.tsx (1)
src/lib/encryption.ts (1)
  • derive_secret_async (24-73)
src/components/Create.tsx (1)
src/lib/validation.ts (3)
  • validateShareName (389-419)
  • VALIDATION_LIMITS (4-15)
  • validatePositiveInteger (335-369)
src/preload.ts (1)
src/types/index.ts (1)
  • RelayPlan (191-198)
src/__tests__/components/AddShare.test.tsx (1)
src/__tests__/setup.ts (1)
  • mockElectronAPI (191-191)
src/__tests__/lib/ipcSchemas.test.ts (1)
src/lib/ipcSchemas.ts (9)
  • ShareIdSchema (14-17)
  • HexSaltSchema (20-23)
  • RelayUrlSchema (26-26)
  • ShareCredentialSchema (29-31)
  • GroupCredentialSchema (34-36)
  • SaveShareSchema (39-67)
  • RelayPlanArgsSchema (70-75)
  • EchoStartArgsSchema (78-87)
  • EchoStopArgsSchema (90-94)
src/__tests__/lib/echoRelays.test.ts (1)
src/lib/echoRelays.ts (2)
  • normalizeRelayUrl (221-221)
  • computeRelayPlan (143-219)
src/__tests__/lib/validation.test.ts (1)
src/lib/validation.ts (7)
  • VALIDATION_LIMITS (4-15)
  • validatePassword (32-49)
  • validatePasswordLength (467-487)
  • validatePositiveInteger (335-369)
  • validateShareName (389-419)
  • sanitizeUserError (432-458)
  • formatRelayUrl (230-304)
src/components/AddShare.tsx (2)
src/lib/validation.ts (2)
  • VALIDATION_LIMITS (4-15)
  • sanitizeUserError (432-458)
src/types/index.ts (1)
  • DecodedGroup (9-19)
src/components/LoadShare.tsx (1)
src/lib/validation.ts (2)
  • VALIDATION_LIMITS (4-15)
  • sanitizeUserError (432-458)
src/lib/echoRelays.ts (1)
src/types/index.ts (1)
  • RelayPlan (191-198)
src/__tests__/integration/computeRelayPlan.test.ts (2)
webpack.config.cjs (1)
  • path (1-1)
src/__tests__/setup.ts (1)
  • mockElectronAPI (191-191)
src/main.ts (2)
src/lib/echoRelays.ts (1)
  • computeRelayPlan (143-219)
src/lib/ipcSchemas.ts (5)
  • SaveShareSchema (39-67)
  • ShareIdSchema (14-17)
  • RelayPlanArgsSchema (70-75)
  • EchoStartArgsSchema (78-87)
  • EchoStopArgsSchema (90-94)
src/__tests__/integration/clientShareManager.test.ts (2)
src/__tests__/setup.ts (1)
  • mockElectronAPI (191-191)
src/lib/clientShareManager.ts (1)
  • clientShareManager (98-98)
src/lib/clientShareManager.ts (1)
src/types/index.ts (1)
  • IglooShare (44-55)
src/components/SaveShare.tsx (1)
src/lib/validation.ts (1)
  • VALIDATION_LIMITS (4-15)
🪛 LanguageTool
SECURITY_AUDIT_2026-01-06.md

[grammar] ~269-~269: Use a hyphen to join words.
Context: ...m invalid threshold values --- ## High Severity Issues ### 6. ✅ FIXED: Insecur...

(QB_NEW_EN_HYPHEN)


[grammar] ~838-~838: Use a hyphen to join words.
Context: ...")` = NaN silently accepted --- ## Low Severity Issues ### 33. ✅ FIXED: No IPC...

(QB_NEW_EN_HYPHEN)


[grammar] ~976-~976: Use a hyphen to join words.
Context: ...ion fixes covering all critical and high severity React component validation issu...

(QB_NEW_EN_HYPHEN)

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.

1 participant