Skip to content

Harden desktop runtime and add multilingual memory - #169

Merged
pmbstyle merged 11 commits into
mainfrom
deps/security-refresh
Aug 4, 2026
Merged

Harden desktop runtime and add multilingual memory#169
pmbstyle merged 11 commits into
mainfrom
deps/security-refresh

Conversation

@pmbstyle

@pmbstyle pmbstyle commented Aug 3, 2026

Copy link
Copy Markdown
Owner

Summary

  • upgrade the Electron stack and tighten renderer/main IPC, navigation, local-file, URL, and command boundaries
  • protect persisted secrets and migrate existing settings into encrypted storage
  • migrate local Memory and RAG embeddings to multilingual E5 with automatic first-run reindexing
  • stabilize VAD/ONNX runtime loading and barge-in cancellation state
  • refresh and pin vulnerable transitive dependencies while keeping the local voice pipeline intact

Why

The desktop runtime had accumulated stale dependencies and overly broad renderer capabilities. Local retrieval also performed poorly outside English, while VAD startup and cancellation contained packaging-specific race conditions.

Impact

  • existing Memory and RAG content is reindexed automatically when the embedding model changes
  • provider selection remains user-controlled; VAD, speech recognition, embeddings, and speech synthesis remain local
  • existing stored secrets are migrated into protected storage
  • renderer capabilities are restricted to explicit preload policies and validated main-process handlers
  • dependency audit is clean

Validation

  • npm test — 25 files, 111 tests
  • npx vue-tsc --noEmit
  • npm run build:web
  • npm audit — 0 vulnerabilities
  • go test ./...
  • go vet ./...
  • git diff --check
  • manual Electron voice-loop smoke: VAD → Whisper STT → multilingual embeddings → hosted completion → Piper TTS
  • packaged macOS arm64 DMG smoke: onboarding rendered, backend health passed, and automatic memory migration completed

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features
    • Added multilingual E5-small embeddings with improved query and passage handling.
    • Added automatic migration and rebuilding of local memory and document indexes.
    • Improved multilingual keyword search, including Unicode text.
    • Added local VAD runtime support and more reliable speech interruption handling.
  • Security
    • Strengthened IPC protections, command confirmations, URL validation, and path restrictions.
    • Secrets are now stored separately using encrypted application storage.
  • Bug Fixes
    • Prevented cancelled speech responses from restarting playback.
    • Improved local server binding and startup error handling.
  • Documentation
    • Updated embedding setup and development instructions.

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 153d0145-8af3-4743-aa71-2996b00b5754

📥 Commits

Reviewing files that changed from the base of the PR and between f36041b and d398277.

📒 Files selected for processing (5)
  • electron/main/desktopManager.ts
  • electron/main/memorySearch.ts
  • electron/main/securityBoundaries.ts
  • electron/main/windowManager.ts
  • src/__tests__/securityBoundaries.test.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/tests/securityBoundaries.test.ts
  • electron/main/securityBoundaries.ts
  • electron/main/windowManager.ts
  • electron/main/memorySearch.ts

📝 Walkthrough

Walkthrough

The change replaces MiniLM with pinned multilingual E5-small embeddings, adds query/passage handling and migrations, narrows Electron IPC access, protects settings and filesystem boundaries, updates VAD packaging, and adjusts startup and cancellation behavior.

Changes

Multilingual embedding migration

Layer / File(s) Summary
Pinned model, tokenizer, and API flow
README.md, scripts/setup-embeddings.js, backend/internal/minilm/*, backend/internal/api/embeddings.go, src/services/backendApi.ts, src/services/apiService.ts
The application uses pinned multilingual E5-small ONNX and tokenizer artifacts with SHA-256 validation and typed query and passage inputs.
Vector, RAG, and memory migration
electron/main/thoughtVectorStore.ts, electron/main/ragDocumentStore.ts, electron/main/memoryManager.ts, electron/main/memorySearch.ts
Local vectors and RAG records track the current model. Legacy data is reindexed. Unicode keyword search and serialized indexing are added.

Electron security boundaries

Layer / File(s) Summary
Security contracts and storage
electron/main/securityBoundaries.ts, electron/main/settingsSecurity.ts, electron/main/settingsManager.ts, electron/preload/ipcBridgePolicy.ts, src/vite-env.d.ts
The change adds IPC channel allowlists, HTTP origin validation, root-constrained path resolution, and protected secret-setting storage.
Main-process enforcement
electron/main/desktopManager.ts, electron/main/ipcManager.ts, electron/main/windowManager.ts
Command execution requires confirmation. HTTP requests, local paths, image paths, navigation, and settings changes use validation. Renderer windows enable security controls.
Renderer bridge migration
electron/preload/index.ts, src/**/*.vue, src/composables/*, src/services/*, src/stores/*, src/utils/*
Renderer IPC calls now use typed aliceIPC or desktopAPI bridges. Event callbacks receive direct payloads. Tests cover bridge and boundary behavior.

Runtime and lifecycle updates

Layer / File(s) Summary
VAD runtime packaging
build/vadAssets.ts, vite.config.ts, src/composables/vadRuntime.ts, src/composables/useAudioProcessing.ts, src/__tests__/vadRuntime.test.ts
VAD and ONNX Runtime assets use shared copy targets and local WASM paths. VAD startup and destruction are asynchronous.
Startup, networking, and cancellation
backend/internal/server/*, backend/main.go, electron/main/index.ts, src/main.ts, src/modules/conversation/speechQueue.ts, src/router/main.ts, electron/main/updaterManager.ts
Backend and WebSocket services bind to loopback. Startup awaits initialization. Expected HTTP shutdown errors are ignored. Cancelled TTS responses are not queued.
Build support
package.json, backend/go.mod, .github/workflows/build-go-backend.yml
Dependency versions, module requirements, documentation, and CI setup support the updated runtime and tokenizer implementation.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Renderer
  participant aliceIPC
  participant MainProcess
  participant Backend
  participant VectorStore
  Renderer->>aliceIPC: Request embedding with input_type
  aliceIPC->>MainProcess: Validate IPC channel
  MainProcess->>Backend: Send prefixed query or passage text
  Backend->>VectorStore: Return embedding vector
  VectorStore->>MainProcess: Store or reindex current-model vector
  MainProcess->>aliceIPC: Return result
  aliceIPC->>Renderer: Deliver response payload
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.51% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the two primary changes: desktop runtime hardening and multilingual memory support.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch deps/security-refresh

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

@socket-security

socket-security Bot commented Aug 3, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Updatednpm/​@​rollup/​rollup-linux-x64-gnu@​4.40.0 ⏵ 4.62.4100 +11004098 +1100
Updatednpm/​onnxruntime-web@​1.14.0 ⏵ 1.27.066 -3110095 +498 -1100
Updatednpm/​electron-builder@​24.13.3 ⏵ 26.15.399 +110069 +197 +1100
Addednpm/​dompurify@​3.4.121001001009370
Updatednpm/​googleapis@​149.0.0 ⏵ 166.0.075 -11100100 +190 -1100
Updatednpm/​vue-tsc@​2.2.10 ⏵ 2.2.1210010075 +196100
Addedgolang/​github.com/​sugarme/​tokenizer@​v0.3.078100100100100
Updatednpm/​openai@​5.0.2 ⏵ 6.33.078 +13100100 +1100 +1100
Updatednpm/​electron-updater@​6.6.2 ⏵ 6.8.99510078 +195 -1100
Updatednpm/​@​ricky0123/​vad-web@​0.0.24 ⏵ 0.0.3010010078 +183100
Addednpm/​vitest@​4.1.10981007998100
Addednpm/​marked@​15.0.121001001009680
Addednpm/​pdfjs-dist@​5.7.28498100829280
Updatednpm/​postcss@​8.5.6 ⏵ 8.5.25100 +1100 +2481 -195100
Updatednpm/​bufferutil@​4.0.9 ⏵ 4.1.0100 +11009281 -3100
Addednpm/​cross-env@​10.1.010010010081100
Updatednpm/​pinia@​3.0.3 ⏵ 3.0.49510081 +189 +9100
Addednpm/​mammoth@​1.12.09910010082100
Updatednpm/​vite@​6.3.4 ⏵ 6.4.391 -2100 +278298100
Updatednpm/​groq-sdk@​0.29.0 ⏵ 1.3.083 -12100100 +196100
Updatednpm/​daisyui@​5.0.50 ⏵ 5.4.5100 +110083 +192100
Updatednpm/​tailwindcss@​4.1.4 ⏵ 4.3.310010084 -198100
Addednpm/​cheerio@​1.1.28810010084100
Updatednpm/​electron-log@​5.4.0 ⏵ 5.4.399 +110010084100
Addednpm/​turndown@​7.2.410010010084100
Updatednpm/​dotenv@​9.0.2 ⏵ 17.4.299100100 +187100
Updatednpm/​minimatch@​5.1.6 ⏵ 9.0.7100100 +31100 +188 -4100
Updatednpm/​better-sqlite3@​11.10.0 ⏵ 12.11.18810010094 +1100
Updatednpm/​picomatch@​2.3.1 ⏵ 4.0.4100 +1100 +1810088100
Updatednpm/​autoprefixer@​10.4.21 ⏵ 10.5.0100 +110089 -292100
Updatednpm/​@​tailwindcss/​vite@​4.1.4 ⏵ 4.3.3100 +110089 +1698100
Updatednpm/​@​vitejs/​plugin-vue@​5.2.3 ⏵ 5.2.49910010089 +1100
See 10 more rows in the dashboard

View full report

@pmbstyle pmbstyle self-assigned this Aug 3, 2026
@pmbstyle
pmbstyle marked this pull request as ready for review August 3, 2026 23:16

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 15

Caution

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

⚠️ Outside diff range comments (4)
src/utils/functions/filesystem.ts (1)

48-61: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Guard the desktopAPI bridge as open_path does.

open_path checks window.aliceIPC?.invoke and returns a clear error. list_directory at Line 52 and execute_command at Line 67 call window.desktopAPI without a guard. If the bridge is absent, both throw a TypeError, and the catch block returns that opaque message to the model instead of a clear reason.

🛡️ Proposed guard for both functions
+function requireDesktopAPI(): NonNullable<typeof window.desktopAPI> {
+  if (typeof window === 'undefined' || !window.desktopAPI) {
+    throw new Error(
+      'Desktop bridge not available. This function only works in the desktop app.'
+    )
+  }
+  return window.desktopAPI
+}
+
 export async function list_directory(
   args: ListDirectoryArgs
 ): Promise<FunctionResult> {
   try {
-    const result = await window.desktopAPI.listDirectory(args.path)
+    const result = await requireDesktopAPI().listDirectory(args.path)

Apply the same call in execute_command:

const result = await requireDesktopAPI().executeCommand(args.command)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/utils/functions/filesystem.ts` around lines 48 - 61, Guard the desktop
bridge in both list_directory and execute_command by reusing
requireDesktopAPI(), matching the existing open_path behavior. Replace direct
window.desktopAPI calls with the required bridge access so missing APIs return
the established clear error instead of an opaque TypeError, while preserving the
existing success and failure result handling.
src/composables/useAudioProcessing.ts (1)

330-340: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Reset the global listener registration state during cleanup.

After Line 331 removes the listeners, ipcListenersRegistered remains true. If this composable mounts again, Line 85 skips registration and global hotkeys stop working.

Proposed fix
   onUnmounted(() => {
     destroyVAD()
     if (window.aliceIPC) {
       window.aliceIPC.off('global-hotkey-mic-toggle', handleGlobalMicToggle)
       window.aliceIPC.off(
         'global-hotkey-mute-playback',
         handleGlobalMutePlayback
       )
       window.aliceIPC.off(
         'global-hotkey-take-screenshot',
         handleGlobalTakeScreenshot
       )
     }
+    ipcListenersRegistered = false
   })
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/composables/useAudioProcessing.ts` around lines 330 - 340, Update the
cleanup block in useAudioProcessing after removing the global hotkey listeners
to reset ipcListenersRegistered to false. Ensure subsequent composable mounts
can pass the registration guard and re-register all global listeners.
src/components/Chat.vue (1)

248-262: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Remove the window.open fallback and validate external URLs in the main process. electron:open-path sends every http://, https://, and mailto: target directly to shell.openExternal without URL validation. Both setWindowOpenHandler handlers deny popups but call shell.openExternal for every HTTP(S) URL before returning deny. No navigation handler enforces the policy.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/Chat.vue` around lines 248 - 262, Remove both
window.open(href, '_blank', 'noopener,noreferrer') fallbacks from the
electron:open-path success and error paths in Chat.vue, and rely solely on the
IPC result. In the main-process electron:open-path handler and both
setWindowOpenHandler handlers, validate targets against the approved external
URL schemes and destinations before calling shell.openExternal; reject invalid
URLs and preserve popup denial without opening them.
backend/internal/minilm/onnx_embeddings.go (1)

329-343: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Propagate tokenizer failures.

Line 329 discards EncodeSingle errors. The method then returns zero IDs and a zero attention mask. GenerateEmbeddings returns a successful zero vector for that text.

Return the tokenizer error through encode and batchTokenize. Stop the embedding request when tokenization fails.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/internal/minilm/onnx_embeddings.go` around lines 329 - 343, The
tokenizer error from EncodeSingle in encode is currently discarded; propagate it
through encode and batchTokenize, updating their signatures and callers as
needed. Ensure GenerateEmbeddings stops and returns the error when tokenization
fails instead of producing a zero-vector embedding, while preserving normal
padding and truncation behavior.
🧹 Nitpick comments (8)
electron/main/settingsManager.ts (1)

261-268: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Write the protected secrets file atomically.

writePrivateFile truncates the target and then writes. alice-secrets.bin is the only copy of the credentials after migration removes the plaintext values. If the process stops between truncation and completion, the file is empty or partial, loadEncryptedSecrets throws, and the user must re-enter every credential.

Write to a temporary file in the same directory and then rename it. fs.rename is atomic within one filesystem.

♻️ Proposed atomic write
 async function writePrivateFile(
   filePath: string,
   data: string | Buffer,
   encoding?: BufferEncoding
 ): Promise<void> {
-  await fs.writeFile(filePath, data, { encoding, mode: 0o600 })
-  await fs.chmod(filePath, 0o600)
+  const tempPath = `${filePath}.${process.pid}.tmp`
+  try {
+    await fs.writeFile(tempPath, data, { encoding, mode: 0o600 })
+    await fs.chmod(tempPath, 0o600)
+    await fs.rename(tempPath, filePath)
+  } catch (error) {
+    await fs.rm(tempPath, { force: true })
+    throw error
+  }
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@electron/main/settingsManager.ts` around lines 261 - 268, Update
writePrivateFile to write the data to a uniquely named temporary file in the
target file’s directory with mode 0o600, then atomically replace the target
using fs.rename; ensure temporary-file cleanup on failure while preserving the
existing encoding and permissions.
src/utils/functions/filesystem.ts (1)

63-67: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Remove the obsolete renderer approval state

The main process now prompts for every command and supports only “Run once”. Remove approvedCommands, the unused approval helpers, and the Security settings UI, which incorrectly claims that commands can run without approval.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/utils/functions/filesystem.ts` around lines 63 - 67, Remove the obsolete
approvedCommands state and its associated approval helper functions, then remove
the Security settings UI and any references to it. Update command execution
around execute_command to rely solely on the main process prompt and “Run once”
behavior, with no renderer-side approval or persistent command authorization.
electron/preload/index.ts (1)

77-81: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider removing only tracked wrappers in removeAllListeners.

ipcRenderer.removeAllListeners(channel) detaches every listener on the channel. If two renderer modules subscribe to the same event, such as overlay-shown, then one module's cleanup removes the other module's handler. Removing only the wrappers tracked in listenerWrappers keeps modules isolated.

♻️ Proposed change
   removeAllListeners(channel: string) {
     assertAllowedChannel(channel, isAllowedEventChannel, 'event')
-    ipcRenderer.removeAllListeners(channel)
-    listenerWrappers.delete(channel)
+    const channelListeners = listenerWrappers.get(channel)
+    if (channelListeners) {
+      for (const wrappers of channelListeners.values()) {
+        for (const wrapper of wrappers) {
+          ipcRenderer.off(channel, wrapper)
+        }
+      }
+      listenerWrappers.delete(channel)
+    }
   },
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@electron/preload/index.ts` around lines 77 - 81, Update removeAllListeners to
remove only the listener wrappers tracked for the specified channel instead of
calling ipcRenderer.removeAllListeners(channel), then clear that channel’s
tracked wrappers from listenerWrappers. Preserve channel validation and ensure
unrelated modules’ listeners remain attached.
src/composables/useScreenshot.ts (1)

68-76: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Make the aliceIPC access pattern consistent.

Line 14 derives isElectron from window.electron, not from window.aliceIPC. Line 68 uses optional chaining, but lines 72 and 76 do not. If the preload exposes electron without aliceIPC, then line 72 throws and listener setup aborts silently. Gate the block on window.aliceIPC instead.

♻️ Proposed change
   const setupScreenshotListeners = () => {
-    if (isElectron) {
+    if (isElectron && window.aliceIPC) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/composables/useScreenshot.ts` around lines 68 - 76, Update the
listener-registration block around handleScreenshotCapturedListener and
handleOverlayClosedListener to first verify that window.aliceIPC exists, rather
than relying on the isElectron check derived from window.electron. Keep both
aliceIPC.on registrations inside that guard so missing aliceIPC skips setup
without throwing.
electron/main/ragDocumentStore.ts (1)

105-105: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Align the rag_chunks.embedding_model default in the CREATE TABLE statements.

rag_documents uses RAG_EMBEDDING_MODEL as the column default. rag_chunks uses LEGACY_RAG_EMBEDDING_MODEL. In CREATE TABLE IF NOT EXISTS the default applies to a fresh database, where no legacy chunk can exist. All current insert paths pass embedding_model explicitly, so behavior is correct today. If a later insert omits the column, new chunks are marked legacy, countLegacyEmbeddings keeps returning a nonzero count, and reindexRagIfNeeded reindexes on every launch.

Use the legacy default only in ensureRagEmbeddingModelColumns, where it describes pre-existing rows.

♻️ Proposed change
-      embedding_model TEXT NOT NULL DEFAULT '${LEGACY_RAG_EMBEDDING_MODEL}',
+      embedding_model TEXT NOT NULL DEFAULT '${RAG_EMBEDDING_MODEL}',

Apply this to both rag_chunks definitions (Line 118 and Line 156). Keep the legacy default in ensureRagEmbeddingModelColumns.

Also applies to: 118-118, 144-144, 156-156

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@electron/main/ragDocumentStore.ts` at line 105, Update both rag_chunks CREATE
TABLE definitions in the relevant initialization paths to use
RAG_EMBEDDING_MODEL as the embedding_model default, matching rag_documents. Keep
LEGACY_RAG_EMBEDDING_MODEL only in ensureRagEmbeddingModelColumns for existing
rows and migration handling.
src/services/backendApi.ts (1)

367-375: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Document the divergent default input types.

generateEmbedding defaults to query and generateEmbeddings defaults to passage. The asymmetry is easy to miss. A caller that batches user queries receives passage prefixes and gets degraded retrieval scores, with no error. Add a short doc note on each method, or require the parameter explicitly.

♻️ Proposed doc clarification
   /**
-   * Generate embedding for text
+   * Generate embedding for text.
+   * Defaults to the `query` input type, because single-text calls are
+   * retrieval queries. Pass `passage` when embedding stored content.
    */
   async generateEmbedding(
   /**
-   * Generate embeddings for multiple texts
+   * Generate embeddings for multiple texts.
+   * Defaults to the `passage` input type, because batch calls are indexing
+   * runs. Pass `query` when embedding a batch of retrieval queries.
    */
   async generateEmbeddings(

Also applies to: 391-399

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/services/backendApi.ts` around lines 367 - 375, Document the differing
defaults in generateEmbedding and generateEmbeddings: identify that the
single-text method defaults inputType to query while the batch method defaults
to passage, and state when callers should choose each type. Keep the current
defaults and behavior unchanged unless making inputType required is necessary.
electron/main/index.ts (1)

7-16: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Move app.disableHardwareAcceleration() below all imports.

ES module imports are hoisted. The call at Line 9 runs after every import in this file is evaluated, including ./thoughtVectorStore and ./ragDocumentStore at Lines 11-16. The placement suggests it runs before those module side effects, and it does not.

The call still happens before the ready event, so behavior is correct. Moving it below the import block removes the misleading ordering.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@electron/main/index.ts` around lines 7 - 16, Move the
app.disableHardwareAcceleration() call below the complete import block in
electron/main/index.ts, including the thoughtVectorStore and ragDocumentStore
imports, while keeping it before application initialization or ready-event
handling.
electron/main/thoughtVectorStore.ts (1)

302-315: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Consider bounding the pending-row selection.

Both .all() calls materialize every pending row, including the full text_content and content values, in the main process before any batching starts. For a large history this is one large allocation on top of the per-batch slices.

Selecting one batch at a time keeps memory bounded and preserves the existing idempotency, because each update already filters on embedding_local IS NULL.

const selectBatch = db.prepare(
  'SELECT thought_id as id, text_content as text FROM thoughts WHERE embedding_local IS NULL LIMIT ?'
)
// loop: read a batch, embed it, update it, repeat until the batch is empty.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@electron/main/thoughtVectorStore.ts` around lines 302 - 315, Update the
pending-row processing around the thoughts and memories queries to fetch bounded
batches instead of materializing all rows with unbounded .all() calls. Reuse
prepared batch queries with a LIMIT, repeatedly embed and update each batch, and
stop when a batch is empty; preserve the existing embedding_local IS NULL
filters and waitForLocalEmbeddingsReady behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@backend/internal/api/embeddings.go`:
- Around line 29-38: Update prefixEmbeddingText to distinguish an omitted
inputType from an explicitly provided value: preserve passage as the default
when omitted, accept only query or passage, and reject any other explicit value
such as "qurey" instead of silently applying the passage prefix. Propagate the
validation error through the embedding request flow.

In `@backend/internal/minilm/tokenizer_test.go`:
- Around line 12-15: Update the Go backend workflow before the go test step to
run npm run setup:embeddings, ensuring the multilingual tokenizer artifact
required by the tokenizer tests is installed and the test is not skipped.

In `@electron/main/desktopManager.ts`:
- Around line 51-76: Update the approval dialog in the command execution handler
to display only a bounded excerpt of command, rather than the full accepted
input. When truncation occurs, append a clear indication that the command is
truncated, while preserving the existing confirmation flow and using the bounded
text for both dialog variants.
- Around line 78-90: Update the exec call in the surrounding command-execution
method to configure both a finite timeout and an appropriately increased
maxBuffer. In its callback, use only the error argument to determine success;
when no error exists, resolve success while preserving stdout and including
stderr as additional context instead of treating it as failure. Keep genuine
execution errors on the failure path.

In `@electron/main/ipcManager.ts`:
- Around line 1225-1229: Cache the result of getAllowedHttpOrigins(settings) in
the main-process HTTP bridge instead of calling loadSettings() for every request
and stream start. Reuse the cached allowed-origin set in the handlers around
validateHttpBridgeUrl, and invalidate or refresh that cache in the existing
settings:save handler so saved settings take effect immediately.

In `@electron/main/memoryManager.ts`:
- Around line 126-136: Replace the ASCII-only LIKE matching in the memory search
flow with the existing FTS5/unicode61 approach used by ragDocumentStore.ts,
querying long_term_memories with prefix terms so tokenized non-ASCII queries
match stored content and avoid leading-wildcard scans. Preserve the memoryType
filter, created_at ordering, and limit behavior.

In `@electron/main/ragDocumentStore.ts`:
- Around line 1331-1346: Update countLegacyEmbeddings() to count only legacy
documents whose paths are included in the configured normalizedTargets used by
pruneMissingDocuments(), or explicitly exclude and resolve out-of-scope legacy
rows. Ensure reindexRagIfNeeded() does not repeatedly retry legacy documents
outside the configured paths.

In `@electron/main/settingsManager.ts`:
- Around line 101-121: Update saveSettings around splitSecretSettings and the
empty-secrets branch to use the returned hadSecretFields flag: only clear the
encrypted secrets file when secret fields were submitted and resolved to empty
values, while preserving stored credentials for partial settings without secret
keys. Add a test in settingsSecurity.test.ts asserting hadSecretFields is false
when no secret key is present.

In `@electron/main/thoughtVectorStore.ts`:
- Around line 185-197: In the migration flow containing
LOCAL_EMBEDDING_INVALIDATION_FLAG and hnswLocalIndexFilePath, move the database
flag update until after the stale HNSW index removal completes successfully.
Preserve the outer failure handling so unlinkSync errors propagate to retry the
migration on the next launch; do not mark the migration flag before deletion
succeeds.

In `@electron/preload/index.ts`:
- Around line 152-153: Update the executeCommand API and its
desktop:executeCommand handler to accept only structured commands from an
explicit allowlist rather than passing arbitrary strings to child_process.exec.
Validate the command name and permitted arguments before execution, reject
unknown or malformed requests, and preserve user confirmation for allowed
commands.

In `@electron/preload/ipcBridgePolicy.ts`:
- Around line 3-81: Unify the desktop IPC bridge with the central allowlist: in
electron/preload/ipcBridgePolicy.ts lines 3-81, add desktop:listDirectory and
desktop:executeCommand to INVOKE_CHANNELS; in electron/preload/index.ts lines
149-155, update both desktopAPI methods to call aliceIPC.invoke so
assertAllowedChannel is applied consistently. Confirm renderer filesystem
helpers use this bridge and preserve their existing behavior.

In `@package.json`:
- Around line 63-84: Add onnxruntime-web as a pinned direct dependency in the
package.json dependencies list, then regenerate package-lock.json so the direct
dependency and its resolved package metadata are recorded. Keep the existing
build/vadAssets.ts and vite.config.ts resolution behavior unchanged.

In `@scripts/setup-embeddings.js`:
- Around line 147-166: Update the platform setup try/catch around downloadFile,
extractArchive, and the copy logic to validate each archive or extracted library
against a configured expected SHA-256 before copying. Treat missing files,
checksum mismatches, download, extraction, and copy errors as failures by
rethrowing from the catch instead of only logging, so the overall setup cannot
report success after a platform error.
- Around line 239-241: Update the main-module check around main() to compare
import.meta.url with pathToFileURL(process.argv[1]).href, and only perform the
comparison when process.argv[1] is defined. Import or reuse the pathToFileURL
utility as needed while preserving the existing behavior of invoking main() for
the entrypoint.

In `@src/services/llmProviders/mainProcessStream.ts`:
- Around line 70-87: The stream cleanup around the abort listener must remove
the registered abort handler when the stream finishes, not only rely on `{ once:
true }`. Update the cleanup/finally path for the listener and `abort` symbols to
call removeEventListener on the same signal, preserving cancellation behavior
while preventing stale http:stream-cancel requests.

---

Outside diff comments:
In `@backend/internal/minilm/onnx_embeddings.go`:
- Around line 329-343: The tokenizer error from EncodeSingle in encode is
currently discarded; propagate it through encode and batchTokenize, updating
their signatures and callers as needed. Ensure GenerateEmbeddings stops and
returns the error when tokenization fails instead of producing a zero-vector
embedding, while preserving normal padding and truncation behavior.

In `@src/components/Chat.vue`:
- Around line 248-262: Remove both window.open(href, '_blank',
'noopener,noreferrer') fallbacks from the electron:open-path success and error
paths in Chat.vue, and rely solely on the IPC result. In the main-process
electron:open-path handler and both setWindowOpenHandler handlers, validate
targets against the approved external URL schemes and destinations before
calling shell.openExternal; reject invalid URLs and preserve popup denial
without opening them.

In `@src/composables/useAudioProcessing.ts`:
- Around line 330-340: Update the cleanup block in useAudioProcessing after
removing the global hotkey listeners to reset ipcListenersRegistered to false.
Ensure subsequent composable mounts can pass the registration guard and
re-register all global listeners.

In `@src/utils/functions/filesystem.ts`:
- Around line 48-61: Guard the desktop bridge in both list_directory and
execute_command by reusing requireDesktopAPI(), matching the existing open_path
behavior. Replace direct window.desktopAPI calls with the required bridge access
so missing APIs return the established clear error instead of an opaque
TypeError, while preserving the existing success and failure result handling.

---

Nitpick comments:
In `@electron/main/index.ts`:
- Around line 7-16: Move the app.disableHardwareAcceleration() call below the
complete import block in electron/main/index.ts, including the
thoughtVectorStore and ragDocumentStore imports, while keeping it before
application initialization or ready-event handling.

In `@electron/main/ragDocumentStore.ts`:
- Line 105: Update both rag_chunks CREATE TABLE definitions in the relevant
initialization paths to use RAG_EMBEDDING_MODEL as the embedding_model default,
matching rag_documents. Keep LEGACY_RAG_EMBEDDING_MODEL only in
ensureRagEmbeddingModelColumns for existing rows and migration handling.

In `@electron/main/settingsManager.ts`:
- Around line 261-268: Update writePrivateFile to write the data to a uniquely
named temporary file in the target file’s directory with mode 0o600, then
atomically replace the target using fs.rename; ensure temporary-file cleanup on
failure while preserving the existing encoding and permissions.

In `@electron/main/thoughtVectorStore.ts`:
- Around line 302-315: Update the pending-row processing around the thoughts and
memories queries to fetch bounded batches instead of materializing all rows with
unbounded .all() calls. Reuse prepared batch queries with a LIMIT, repeatedly
embed and update each batch, and stop when a batch is empty; preserve the
existing embedding_local IS NULL filters and waitForLocalEmbeddingsReady
behavior.

In `@electron/preload/index.ts`:
- Around line 77-81: Update removeAllListeners to remove only the listener
wrappers tracked for the specified channel instead of calling
ipcRenderer.removeAllListeners(channel), then clear that channel’s tracked
wrappers from listenerWrappers. Preserve channel validation and ensure unrelated
modules’ listeners remain attached.

In `@src/composables/useScreenshot.ts`:
- Around line 68-76: Update the listener-registration block around
handleScreenshotCapturedListener and handleOverlayClosedListener to first verify
that window.aliceIPC exists, rather than relying on the isElectron check derived
from window.electron. Keep both aliceIPC.on registrations inside that guard so
missing aliceIPC skips setup without throwing.

In `@src/services/backendApi.ts`:
- Around line 367-375: Document the differing defaults in generateEmbedding and
generateEmbeddings: identify that the single-text method defaults inputType to
query while the batch method defaults to passage, and state when callers should
choose each type. Keep the current defaults and behavior unchanged unless making
inputType required is necessary.

In `@src/utils/functions/filesystem.ts`:
- Around line 63-67: Remove the obsolete approvedCommands state and its
associated approval helper functions, then remove the Security settings UI and
any references to it. Update command execution around execute_command to rely
solely on the main process prompt and “Run once” behavior, with no renderer-side
approval or persistent command authorization.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: cd1f9c5a-27bd-4552-8f76-c622b46bc2d8

📥 Commits

Reviewing files that changed from the base of the PR and between 3b055d5 and b76acaf.

⛔ Files ignored due to path filters (2)
  • backend/go.sum is excluded by !**/*.sum
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (66)
  • README.md
  • backend/go.mod
  • backend/internal/api/embeddings.go
  • backend/internal/api/embeddings_test.go
  • backend/internal/minilm/onnx_embeddings.go
  • backend/internal/minilm/tokenizer_test.go
  • backend/internal/minilm/types.go
  • backend/internal/models/manager.go
  • backend/internal/server/server.go
  • backend/internal/server/server_test.go
  • backend/main.go
  • build/vadAssets.ts
  • electron/main/desktopManager.ts
  • electron/main/index.ts
  • electron/main/ipcManager.ts
  • electron/main/memoryManager.ts
  • electron/main/ragDocumentStore.ts
  • electron/main/securityBoundaries.ts
  • electron/main/settingsManager.ts
  • electron/main/settingsSecurity.ts
  • electron/main/thoughtVectorStore.ts
  • electron/main/updaterManager.ts
  • electron/main/windowManager.ts
  • electron/preload/index.ts
  • electron/preload/ipcBridgePolicy.ts
  • package.json
  • scripts/setup-embeddings.js
  • src/App.vue
  • src/__tests__/ipcBridgePolicy.test.ts
  • src/__tests__/securityBoundaries.test.ts
  • src/__tests__/settingsSecurity.test.ts
  • src/__tests__/vadRuntime.test.ts
  • src/components/Actions.vue
  • src/components/Chat.vue
  • src/components/Main.vue
  • src/components/MemoryManager.vue
  • src/components/Overlay.vue
  • src/components/Settings.vue
  • src/components/SettingsWindow.vue
  • src/components/Sidebar.vue
  • src/components/settings/CoreSettingsTab.vue
  • src/components/wizard/OnboardingWizard.vue
  • src/composables/useAudioProcessing.ts
  • src/composables/useCodexAuth.ts
  • src/composables/useGoogleAuth.ts
  • src/composables/useScreenshot.ts
  • src/composables/vadRuntime.ts
  • src/main.ts
  • src/modules/conversation/__tests__/speechQueue.test.ts
  • src/modules/conversation/speechQueue.ts
  • src/router/main.ts
  • src/services/apiService.ts
  • src/services/backendApi.ts
  • src/services/llmProviders/__tests__/codex.test.ts
  • src/services/llmProviders/__tests__/openAICompatible.test.ts
  • src/services/llmProviders/codex.ts
  • src/services/llmProviders/codexToolBridge.ts
  • src/services/llmProviders/mainProcessStream.ts
  • src/stores/conversationStore.ts
  • src/stores/customToolsStore.ts
  • src/utils/functionCaller.ts
  • src/utils/functions/calendar.ts
  • src/utils/functions/clipboard.ts
  • src/utils/functions/filesystem.ts
  • src/vite-env.d.ts
  • vite.config.ts

Comment thread backend/internal/api/embeddings.go Outdated
Comment thread backend/internal/minilm/tokenizer_test.go
Comment thread electron/main/desktopManager.ts
Comment on lines +78 to +90
return new Promise(resolve => {
exec(command, (error, stdout, stderr) => {
if (error) {
resolve({ success: false, error: error.message })
return
}
if (stderr) {
resolve({ success: false, error: stderr })
return
}
resolve({ success: true, output: stdout })
})
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Bound the command execution and stop treating stderr as failure.

Two problems exist in this block.

  1. A command that exits with code 0 and writes to stderr is reported as a failure, and its stdout is discarded. Many tools write progress and warnings to stderr. Use the error argument to decide success, and return stderr as additional context.
  2. exec runs with no timeout and the default maxBuffer. A command that never exits leaves the promise pending forever. A command with large output rejects with ENOBUFS after the work is already done. Set both options.
🐛 Proposed fix for classification and bounds
         return new Promise(resolve => {
-          exec(command, (error, stdout, stderr) => {
-            if (error) {
-              resolve({ success: false, error: error.message })
-              return
-            }
-            if (stderr) {
-              resolve({ success: false, error: stderr })
-              return
-            }
-            resolve({ success: true, output: stdout })
-          })
+          exec(
+            command,
+            { timeout: 60_000, maxBuffer: 10 * 1024 * 1024 },
+            (error, stdout, stderr) => {
+              if (error) {
+                resolve({ success: false, error: error.message, output: stdout })
+                return
+              }
+              resolve({ success: true, output: stdout, stderr })
+            }
+          )
         })
📝 Committable suggestion

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

Suggested change
return new Promise(resolve => {
exec(command, (error, stdout, stderr) => {
if (error) {
resolve({ success: false, error: error.message })
return
}
if (stderr) {
resolve({ success: false, error: stderr })
return
}
resolve({ success: true, output: stdout })
})
})
return new Promise(resolve => {
exec(
command,
{ timeout: 60_000, maxBuffer: 10 * 1024 * 1024 },
(error, stdout, stderr) => {
if (error) {
resolve({ success: false, error: error.message, output: stdout })
return
}
resolve({ success: true, output: stdout, stderr })
}
)
})
🧰 Tools
🪛 OpenGrep (1.26.0)

[ERROR] 79-89: Dynamic command passed to child_process.exec/execSync. Use child_process.execFile or spawn with an argument array instead.

(coderabbit.command-injection.exec-js)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@electron/main/desktopManager.ts` around lines 78 - 90, Update the exec call
in the surrounding command-execution method to configure both a finite timeout
and an appropriately increased maxBuffer. In its callback, use only the error
argument to determine success; when no error exists, resolve success while
preserving stdout and including stderr as additional context instead of treating
it as failure. Keep genuine execution errors on the failure path.

Source: Linters/SAST tools

Comment thread electron/main/ipcManager.ts Outdated
Comment thread electron/preload/ipcBridgePolicy.ts
Comment thread package.json
Comment thread scripts/setup-embeddings.js Outdated
Comment thread scripts/setup-embeddings.js
Comment on lines +70 to +87
const listener = (event: StreamQueueEvent) => {
pushEvent(event)
}

const abort = () => {
void window.ipcRenderer.invoke('http:stream-cancel', { requestId })
void window.aliceIPC.invoke('http:stream-cancel', { requestId })
pushEvent({ type: 'error', error: 'The operation was aborted.' })
}

window.ipcRenderer.on(channel, listener as any)
window.aliceIPC.on(channel, listener as any)
signal?.addEventListener('abort', abort, { once: true })

try {
if (signal?.aborted) {
throw createAbortError()
}

const startResult = await window.ipcRenderer.invoke('http:stream-start', {
const startResult = await window.aliceIPC.invoke('http:stream-start', {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Remove the abort listener during stream cleanup.

If the stream completes before abort, { once: true } does not remove the listener. A later signal abort retains this request closure and sends a stale http:stream-cancel request.

Proposed fix
   } finally {
+    signal?.removeEventListener('abort', abort)
     window.aliceIPC.off(channel, listener as any)
     void window.aliceIPC.invoke('http:stream-cancel', { requestId })
   }

Also applies to: 122-123

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/services/llmProviders/mainProcessStream.ts` around lines 70 - 87, The
stream cleanup around the abort listener must remove the registered abort
handler when the stream finishes, not only rely on `{ once: true }`. Update the
cleanup/finally path for the listener and `abort` symbols to call
removeEventListener on the same signal, preserving cancellation behavior while
preventing stale http:stream-cancel requests.

@socket-security

socket-security Bot commented Aug 3, 2026

Copy link
Copy Markdown

Warning

Review the following alerts detected in dependencies.

According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.

Action Severity Alert  (click "▶" to expand/collapse)
Warn High
Obfuscated code: npm better-sqlite3 is 90.0% likely obfuscated

Confidence: 0.90

Location: Package overview

From: package-lock.jsonnpm/better-sqlite3@12.11.1

ℹ Read more on: This package | This alert | What is obfuscated code?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Packages should not obfuscate their code. Consider not using packages with obfuscated code.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/better-sqlite3@12.11.1. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn High
Obfuscated code: npm electron-winstaller is 90.0% likely obfuscated

Confidence: 0.90

Location: Package overview

From: package-lock.jsonnpm/electron-builder@26.15.3npm/electron-winstaller@5.4.0

ℹ Read more on: This package | This alert | What is obfuscated code?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Packages should not obfuscate their code. Consider not using packages with obfuscated code.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/electron-winstaller@5.4.0. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn High
Obfuscated code: npm onnxruntime-web is 90.0% likely obfuscated

Confidence: 0.90

Location: Package overview

From: package-lock.jsonnpm/onnxruntime-web@1.27.0

ℹ Read more on: This package | This alert | What is obfuscated code?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Packages should not obfuscate their code. Consider not using packages with obfuscated code.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/onnxruntime-web@1.27.0. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn High
Obfuscated code: npm onnxruntime-web is 90.0% likely obfuscated

Confidence: 0.90

Location: Package overview

From: package-lock.jsonnpm/onnxruntime-web@1.27.0

ℹ Read more on: This package | This alert | What is obfuscated code?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Packages should not obfuscate their code. Consider not using packages with obfuscated code.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/onnxruntime-web@1.27.0. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn High
Obfuscated code: npm onnxruntime-web is 90.0% likely obfuscated

Confidence: 0.90

Location: Package overview

From: package-lock.jsonnpm/onnxruntime-web@1.27.0

ℹ Read more on: This package | This alert | What is obfuscated code?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Packages should not obfuscate their code. Consider not using packages with obfuscated code.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/onnxruntime-web@1.27.0. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn High
Obfuscated code: npm rimraf is 90.0% likely obfuscated

Confidence: 0.90

Location: Package overview

From: package-lock.jsonnpm/googleapis@166.0.0npm/rimraf@5.0.10

ℹ Read more on: This package | This alert | What is obfuscated code?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Packages should not obfuscate their code. Consider not using packages with obfuscated code.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/rimraf@5.0.10. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn High
Obfuscated code: npm tiny-async-pool is 90.0% likely obfuscated

Confidence: 0.90

Location: Package overview

From: package-lock.jsonnpm/electron-builder@26.15.3npm/tiny-async-pool@1.3.0

ℹ Read more on: This package | This alert | What is obfuscated code?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Packages should not obfuscate their code. Consider not using packages with obfuscated code.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/tiny-async-pool@1.3.0. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn High
Obfuscated code: npm underscore is 90.0% likely obfuscated

Confidence: 0.90

Location: Package overview

From: package-lock.jsonnpm/mammoth@1.12.0npm/underscore@1.13.8

ℹ Read more on: This package | This alert | What is obfuscated code?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Packages should not obfuscate their code. Consider not using packages with obfuscated code.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/underscore@1.13.8. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

View full report

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

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

⚠️ Outside diff range comments (1)
scripts/setup-embeddings.js (1)

88-106: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Handle response-stream failures after a successful status code.

Handle response error and aborted events. Without handlers, the promise can remain pending, and an unhandled error event can terminate the process. Destroy both streams, remove dest, and reject once.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/setup-embeddings.js` around lines 88 - 106, Update the download flow
around response.pipe(file) to handle response error and aborted events even
after a successful status code. For either event, destroy both response and file
streams, remove dest, and reject the promise exactly once; preserve the existing
file-stream and request error cleanup while preventing duplicate rejection or
cleanup.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/build-go-backend.yml:
- Around line 10-14: Update the pull_request.paths list in the workflow trigger
to include .github/workflows/build-go-backend.yml, so changes to the workflow
definition itself run backend validation before merge while preserving the
existing backend and embeddings path filters.

In `@electron/main/memorySearch.ts`:
- Around line 24-36: Update tokenizeMemoryQuery to use locale-independent
toLowerCase() instead of toLocaleLowerCase() before splitting tokens, ensuring
generated FTS tokens match unicode61 indexing across system locales.

In `@electron/main/windowManager.ts`:
- Around line 46-50: Update openExternal to attach a catch handler to the
Promise returned by shell.openExternal, preserving the existing URL validation
and warning behavior while handling asynchronous rejections without unhandled
Promise errors.

In `@electron/preload/ipcBridgePolicy.ts`:
- Line 41: Restrict the desktop:listDirectory bridge and its desktopManager
handling to an approved-directory capability: require a user-approved root,
resolve each renderer-supplied path within that root, and pass only the
validated resolved path to fs.readdir. Do not expose desktop:listDirectory when
this enforcement is unavailable.

---

Outside diff comments:
In `@scripts/setup-embeddings.js`:
- Around line 88-106: Update the download flow around response.pipe(file) to
handle response error and aborted events even after a successful status code.
For either event, destroy both response and file streams, remove dest, and
reject the promise exactly once; preserve the existing file-stream and request
error cleanup while preventing duplicate rejection or cleanup.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 285e07ef-a663-4cf9-ab21-676765763613

📥 Commits

Reviewing files that changed from the base of the PR and between b76acaf and f36041b.

⛔ Files ignored due to path filters (2)
  • bun.lock is excluded by !**/*.lock
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (25)
  • .github/workflows/build-go-backend.yml
  • backend/internal/api/embeddings.go
  • backend/internal/api/embeddings_test.go
  • backend/internal/minilm/onnx_embeddings.go
  • backend/internal/minilm/tokenizer_test.go
  • electron/main/desktopManager.ts
  • electron/main/ipcManager.ts
  • electron/main/memoryManager.ts
  • electron/main/memorySearch.ts
  • electron/main/ragDocumentStore.ts
  • electron/main/securityBoundaries.ts
  • electron/main/settingsManager.ts
  • electron/main/thoughtVectorStore.ts
  • electron/main/windowManager.ts
  • electron/preload/index.ts
  • electron/preload/ipcBridgePolicy.ts
  • package.json
  • scripts/setup-embeddings.js
  • src/__tests__/ipcBridgePolicy.test.ts
  • src/__tests__/memorySearch.test.ts
  • src/__tests__/securityBoundaries.test.ts
  • src/__tests__/settingsSecurity.test.ts
  • src/components/Chat.vue
  • src/composables/useAudioProcessing.ts
  • src/utils/functions/filesystem.ts
💤 Files with no reviewable changes (1)
  • src/components/Chat.vue
🚧 Files skipped from review as they are similar to previous changes (15)
  • backend/internal/api/embeddings_test.go
  • src/tests/settingsSecurity.test.ts
  • src/tests/securityBoundaries.test.ts
  • package.json
  • electron/preload/index.ts
  • src/tests/ipcBridgePolicy.test.ts
  • src/utils/functions/filesystem.ts
  • electron/main/settingsManager.ts
  • src/composables/useAudioProcessing.ts
  • electron/main/securityBoundaries.ts
  • electron/main/memoryManager.ts
  • backend/internal/api/embeddings.go
  • backend/internal/minilm/onnx_embeddings.go
  • electron/main/ipcManager.ts
  • electron/main/ragDocumentStore.ts

Comment on lines 10 to +14
pull_request:
branches: [main]
paths:
- 'backend/**'
- 'scripts/setup-embeddings.js'

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Run this workflow when its PR definition changes.

pull_request.paths does not include .github/workflows/build-go-backend.yml. A pull request that only changes this workflow will not run the backend validation before merge.

Proposed fix
   pull_request:
     branches: [main]
     paths:
       - 'backend/**'
       - 'scripts/setup-embeddings.js'
+      - '.github/workflows/build-go-backend.yml'
📝 Committable suggestion

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

Suggested change
pull_request:
branches: [main]
paths:
- 'backend/**'
- 'scripts/setup-embeddings.js'
pull_request:
branches: [main]
paths:
- 'backend/**'
- 'scripts/setup-embeddings.js'
- '.github/workflows/build-go-backend.yml'
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/build-go-backend.yml around lines 10 - 14, Update the
pull_request.paths list in the workflow trigger to include
.github/workflows/build-go-backend.yml, so changes to the workflow definition
itself run backend validation before merge while preserving the existing backend
and embeddings path filters.

Comment thread electron/main/memorySearch.ts
Comment thread electron/main/windowManager.ts
Comment thread electron/preload/ipcBridgePolicy.ts
@pmbstyle
pmbstyle merged commit 968d821 into main Aug 4, 2026
11 checks passed
@pmbstyle
pmbstyle deleted the deps/security-refresh branch August 4, 2026 10:31
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